@squiz/optimization-utils 1.0.0 → 1.1.0

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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @squiz/optimization-utils
2
+
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - afea2f1: Added the logs lambda handler
@@ -8,6 +8,9 @@ export declare const TENANT_ID_METADATA: (tenantId: string | ValueOf) => {
8
8
  export declare const PROCESSABLE_LOG_METADATA: {
9
9
  readonly processable: true;
10
10
  };
11
+ export declare const REMOTE_LOG_METADATA: {
12
+ readonly remote: true;
13
+ };
11
14
  export type LogMessage = (message: string | any) => [string | any, Record<string, unknown>];
12
15
  export type CreateLog = {
13
16
  attachMetadata: (metadata: Record<string, unknown>) => CreateLog;
@@ -17,6 +20,7 @@ export type CreateLog = {
17
20
  attachExperimentId: (experimentId: string | ValueOf) => CreateLog;
18
21
  attachCaller: <T extends abstract new (...args: any) => any>(caller: InstanceType<T> | string) => CreateLog;
19
22
  isProcessable: () => CreateLog;
23
+ remote: () => CreateLog;
20
24
  getMetadata: () => Record<string, unknown>;
21
25
  create: <T extends abstract new (...args: any) => any>(caller?: InstanceType<T> | string) => LogMessage;
22
26
  };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PROCESSABLE_LOG_METADATA = exports.TENANT_ID_METADATA = void 0;
3
+ exports.REMOTE_LOG_METADATA = exports.PROCESSABLE_LOG_METADATA = exports.TENANT_ID_METADATA = void 0;
4
4
  exports.createLogMessage = createLogMessage;
5
5
  exports.createLog = createLog;
6
6
  const crypto_1 = require("crypto");
@@ -22,6 +22,7 @@ const TENANT_ID_METADATA = (tenantId) => ({
22
22
  });
23
23
  exports.TENANT_ID_METADATA = TENANT_ID_METADATA;
24
24
  exports.PROCESSABLE_LOG_METADATA = { processable: true };
25
+ exports.REMOTE_LOG_METADATA = { remote: true };
25
26
  function createLog(opts) {
26
27
  opts = {
27
28
  metadata: {
@@ -62,6 +63,9 @@ function createLog(opts) {
62
63
  const isProcessable = () => {
63
64
  return attachMetadata(exports.PROCESSABLE_LOG_METADATA);
64
65
  };
66
+ const remote = () => {
67
+ return attachMetadata(exports.REMOTE_LOG_METADATA);
68
+ };
65
69
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
66
70
  const attachCaller = (caller) => {
67
71
  return attachMetadata({
@@ -88,6 +92,7 @@ function createLog(opts) {
88
92
  isProcessable,
89
93
  attachCaller,
90
94
  getMetadata: () => opts?.metadata ?? {},
95
+ remote,
91
96
  create,
92
97
  };
93
98
  }
@@ -1 +1 @@
1
- {"version":3,"file":"LoggerMessage.js","sourceRoot":"","sources":["../../src/logger/LoggerMessage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LoggerMessage.js","sourceRoot":"","sources":["../../src/logger/LoggerMessage.ts"],"names":[],"mappings":";;;AAeA,4CAWC;AAqCD,8BA8FC;AA7JD,mCAAoC;AAMpC,8DAA8D;AAC9D,MAAM,eAAe,GAAG,CACtB,qBAA+C,EACvC,EAAE,CACV,OAAO,qBAAqB,KAAK,QAAQ;IACvC,CAAC,CAAC,qBAAqB;IACvB,CAAC,CAAC,qBAAqB,CAAC,WAAW,CAAC,IAAI,CAAC;AAE7C,8DAA8D;AAC9D,SAAgB,gBAAgB,CAC9B,GAAG,QAAyC;IAE5C,MAAM,OAAO,GAAG,IAAA,mBAAU,GAAE,CAAC;IAE7B,MAAM,iBAAiB,GAAG,CAAC,GAAG,QAAQ,EAAE,YAAY,OAAO,EAAE,CAAC;SAC3D,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;SACxB,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC;SAC3C,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,iBAAiB,IAAI,OAAO,IAAI,EAAE,EAAE,CAAC;AAC9D,CAAC;AAEM,MAAM,kBAAkB,GAAG,CAChC,QAA0B,EAG1B,EAAE,CAAC,CAAC;IACJ,QAAQ,EAAE,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE;CACvE,CAAC,CAAC;AANU,QAAA,kBAAkB,sBAM5B;AAEU,QAAA,wBAAwB,GAAG,EAAE,WAAW,EAAE,IAAI,EAAW,CAAC;AAC1D,QAAA,mBAAmB,GAAG,EAAE,MAAM,EAAE,IAAI,EAAW,CAAC;AA0B7D,SAAgB,SAAS,CAAC,IAGzB;IACC,IAAI,GAAG;QACL,QAAQ,EAAE;YACR,OAAO,EAAE,IAAA,mBAAU,GAAE;YACrB,GAAG,IAAI,EAAE,QAAQ;SAClB;QACD,OAAO,EAAE,IAAI,EAAE,OAAO;KACvB,CAAC;IAEF,MAAM,cAAc,GAAG,CACrB,QAAoD,EACzC,EAAE;QACb,OAAO,SAAS,CAAC;YACf,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC;YACjB,QAAQ,EAAE;gBACR,GAAG,IAAI,EAAE,QAAQ;gBACjB,GAAG,QAAQ;aACZ;SACF,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,cAAc,GAAG,CAAC,QAA0B,EAAa,EAAE;QAC/D,OAAO,cAAc,CAAC,IAAA,0BAAkB,EAAC,QAAQ,CAAC,CAAC,CAAC;IACtD,CAAC,CAAC;IAEF,MAAM,kBAAkB,GAAG,CAAC,YAA8B,EAAa,EAAE;QACvE,OAAO,cAAc,CAAC;YACpB,YAAY,EACV,OAAO,YAAY,KAAK,QAAQ;gBAC9B,CAAC,CAAC,YAAY;gBACd,CAAC,CAAC,YAAY,CAAC,OAAO,EAAE;SAC7B,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,eAAe,GAAG,CAAC,SAAiB,EAAa,EAAE;QACvD,OAAO,cAAc,CAAC;YACpB,SAAS;SACV,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,mBAAmB,GAAG,CAAC,EAAU,EAAa,EAAE;QACpD,OAAO,cAAc,CAAC;YACpB,aAAa,EAAE,EAAE;SAClB,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,GAAc,EAAE;QACpC,OAAO,cAAc,CAAC,gCAAwB,CAAC,CAAC;IAClD,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,GAAc,EAAE;QAC7B,OAAO,cAAc,CAAC,2BAAmB,CAAC,CAAC;IAC7C,CAAC,CAAC;IAEF,8DAA8D;IAC9D,MAAM,YAAY,GAAG,CACnB,MAAkB,EACP,EAAE;QACb,OAAO,cAAc,CAAC;YACpB,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;SAChC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,8DAA8D;IAC9D,MAAM,MAAM,GAAG,CACb,MAAmB,EAEmD,EAAE;QACxE,MAAM,QAAQ,GAAG;YACf,GAAG,IAAI,EAAE,QAAQ;YACjB,GAAG,CAAC,MAAM,IAAI;gBACZ,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC;aAChC,CAAC;SACH,CAAC;QAEF,8DAA8D;QAC9D,OAAO,CAAC,OAAqB,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACxD,CAAC,CAAC;IAEF,OAAO;QACL,cAAc;QACd,cAAc;QACd,kBAAkB;QAClB,eAAe;QACf,mBAAmB;QACnB,aAAa;QACb,YAAY;QACZ,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE;QACvC,MAAM;QACN,MAAM;KACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { CloudWatchLogsEvent } from 'aws-lambda';
2
+ import { RemoteLogger } from './RemoteLogger';
3
+ import { Logger } from './Logger';
4
+ export declare class LogsHandler {
5
+ private readonly remoteLogger;
6
+ private readonly logger;
7
+ constructor(remoteLogger: RemoteLogger, logger: Logger);
8
+ handle(event: CloudWatchLogsEvent): Promise<void>;
9
+ private mapLogs;
10
+ private decodeLogs;
11
+ }
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ var __importDefault = (this && this.__importDefault) || function (mod) {
15
+ return (mod && mod.__esModule) ? mod : { "default": mod };
16
+ };
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.LogsHandler = void 0;
19
+ const zlib_1 = __importDefault(require("zlib"));
20
+ const inversify_1 = require("inversify");
21
+ const util_1 = require("util");
22
+ const RemoteLogger_1 = require("./RemoteLogger");
23
+ const Logger_1 = require("./Logger");
24
+ const LoggerMessage_1 = require("./LoggerMessage");
25
+ let LogsHandler = class LogsHandler {
26
+ remoteLogger;
27
+ logger;
28
+ constructor(remoteLogger, logger) {
29
+ this.remoteLogger = remoteLogger;
30
+ this.logger = logger;
31
+ }
32
+ async handle(event) {
33
+ const logMessage = (0, LoggerMessage_1.createLogMessage)(this);
34
+ this.logger.debug(logMessage(`started mapping CloudWatchLogsEvent`));
35
+ const remoteLogs = this.mapLogs(event, logMessage);
36
+ this.logger.debug(logMessage(`finished mapping CloudWatchLogsEvent`));
37
+ this.logger.debug(logMessage(`started sending logs (count: ${remoteLogs.length}) into the RemoteLogger`));
38
+ await this.remoteLogger.log(remoteLogs);
39
+ this.logger.debug(logMessage('finished sending logs into the RemoteLogger'));
40
+ }
41
+ mapLogs(event, logMessage) {
42
+ const logs = this.decodeLogs(event);
43
+ this.logger.debug(logMessage(`received decoded logs: ${(0, util_1.inspect)(logs, { depth: 4 })}`));
44
+ const isRemoteLog = (log) => !!log;
45
+ return logs
46
+ .map((log) => {
47
+ const result = RemoteLogger_1.REMOTE_LOG_SCHEMA.safeParse(JSON.parse(log.message));
48
+ return result.success ? result.data : undefined;
49
+ })
50
+ .filter(isRemoteLog);
51
+ }
52
+ decodeLogs(event) {
53
+ const payload = Buffer.from(event.awslogs.data, 'base64');
54
+ const logs = JSON.parse(zlib_1.default.unzipSync(payload).toString());
55
+ return logs.logEvents;
56
+ }
57
+ };
58
+ exports.LogsHandler = LogsHandler;
59
+ exports.LogsHandler = LogsHandler = __decorate([
60
+ (0, inversify_1.injectable)(),
61
+ __param(0, (0, inversify_1.inject)(RemoteLogger_1.RemoteLogger)),
62
+ __param(1, (0, inversify_1.inject)(Logger_1.Logger)),
63
+ __metadata("design:paramtypes", [RemoteLogger_1.RemoteLogger,
64
+ Logger_1.Logger])
65
+ ], LogsHandler);
66
+ //# sourceMappingURL=LogsHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LogsHandler.js","sourceRoot":"","sources":["../../src/logger/LogsHandler.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AACA,gDAAwB;AACxB,yCAA+C;AAC/C,+BAA+B;AAE/B,iDAA4E;AAC5E,qCAAkC;AAClC,mDAAmD;AAG5C,IAAM,WAAW,GAAjB,MAAM,WAAW;IAGH;IAEA;IAJnB,YAEmB,YAA0B,EAE1B,MAAc;QAFd,iBAAY,GAAZ,YAAY,CAAc;QAE1B,WAAM,GAAN,MAAM,CAAQ;IAC9B,CAAC;IAEJ,KAAK,CAAC,MAAM,CAAC,KAA0B;QACrC,MAAM,UAAU,GAAG,IAAA,gCAAgB,EAAC,IAAI,CAAC,CAAC;QAE1C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,qCAAqC,CAAC,CAAC,CAAC;QACrE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QAEnD,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,sCAAsC,CAAC,CAAC,CAAC;QAEtE,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,UAAU,CACR,gCAAgC,UAAU,CAAC,MAAM,yBAAyB,CAC3E,CACF,CAAC;QACF,MAAM,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,UAAU,CAAC,6CAA6C,CAAC,CAC1D,CAAC;IACJ,CAAC;IAEO,OAAO,CACb,KAA0B,EAC1B,UAA+C;QAE/C,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAEpC,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,UAAU,CAAC,0BAA0B,IAAA,cAAO,EAAC,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CACpE,CAAC;QACF,MAAM,WAAW,GAAG,CAAC,GAA0B,EAAoB,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC;QAE5E,OAAO,IAAI;aACR,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;YACX,MAAM,MAAM,GAAG,gCAAiB,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;YAEpE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QAClD,CAAC,CAAC;aACD,MAAM,CAAC,WAAW,CAAC,CAAC;IACzB,CAAC;IAEO,UAAU,CAChB,KAA0B;QAE1B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC1D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,cAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;QAE5D,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF,CAAA;AAvDY,kCAAW;sBAAX,WAAW;IADvB,IAAA,sBAAU,GAAE;IAGR,WAAA,IAAA,kBAAM,EAAC,2BAAY,CAAC,CAAA;IAEpB,WAAA,IAAA,kBAAM,EAAC,eAAM,CAAC,CAAA;qCADgB,2BAAY;QAElB,eAAM;GALtB,WAAW,CAuDvB"}
@@ -0,0 +1,13 @@
1
+ import { CloudWatchLogsEvent } from 'aws-lambda';
2
+ import { LogsHandler } from './LogsHandler';
3
+ import { Logger } from './Logger';
4
+ import { Container } from 'inversify';
5
+ export declare const CLOUDWATCH_FILTER_PATTERN = "{ $.level = \"info\" || $.level = \"warn\" || ($.level = \"error\" && $.processable IS TRUE) || $.remote IS TRUE }";
6
+ export type LogsLambdaHandler = (event: CloudWatchLogsEvent) => Promise<{
7
+ status: string;
8
+ }>;
9
+ export declare function createLogsLambdaHandler(instances: {
10
+ logsHandler: LogsHandler;
11
+ logger: Logger;
12
+ }): LogsLambdaHandler;
13
+ export declare function createLogsLambdaHandler(container: Container): LogsLambdaHandler;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CLOUDWATCH_FILTER_PATTERN = void 0;
4
+ exports.createLogsLambdaHandler = createLogsLambdaHandler;
5
+ const LogsHandler_1 = require("./LogsHandler");
6
+ const Logger_1 = require("./Logger");
7
+ const inversify_1 = require("inversify");
8
+ exports.CLOUDWATCH_FILTER_PATTERN = `{ $.level = "info" || $.level = "warn" || ($.level = "error" && $.processable IS TRUE) || $.remote IS TRUE }`;
9
+ function createLogsLambdaHandler(opts) {
10
+ let logsHandler;
11
+ let logger;
12
+ if (opts instanceof inversify_1.Container) {
13
+ logsHandler = opts.get(LogsHandler_1.LogsHandler);
14
+ logger = opts.get(Logger_1.Logger);
15
+ }
16
+ else {
17
+ logsHandler = opts.logsHandler;
18
+ logger = opts.logger;
19
+ }
20
+ return async (event) => {
21
+ try {
22
+ await logsHandler.handle(event);
23
+ return { status: 'ok' };
24
+ }
25
+ catch (e) {
26
+ logger.error(e);
27
+ throw e;
28
+ }
29
+ };
30
+ }
31
+ //# sourceMappingURL=LogsLambdaHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LogsLambdaHandler.js","sourceRoot":"","sources":["../../src/logger/LogsLambdaHandler.ts"],"names":[],"mappings":";;;AAkBA,0DAwBC;AAzCD,+CAA4C;AAC5C,qCAAkC;AAClC,yCAAsC;AAEzB,QAAA,yBAAyB,GAAG,8GAA8G,CAAC;AAaxJ,SAAgB,uBAAuB,CACrC,IAA8D;IAE9D,IAAI,WAAwB,CAAC;IAC7B,IAAI,MAAc,CAAC;IAEnB,IAAI,IAAI,YAAY,qBAAS,EAAE,CAAC;QAC9B,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,yBAAW,CAAC,CAAC;QACpC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,eAAM,CAAC,CAAC;IAC5B,CAAC;SAAM,CAAC;QACN,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;QAC/B,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,OAAO,KAAK,EAAE,KAA0B,EAAE,EAAE;QAC1C,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAEhC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;QAC1B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAChB,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
package/dist/package.d.ts CHANGED
@@ -9,6 +9,7 @@ export * from './logger/SquizRemoteLogger';
9
9
  export * from './logger/RemoteLogger';
10
10
  export * from './logger/LoggerMessage';
11
11
  export * from './logger/Logger';
12
+ export * from './logger/LogsLambdaHandler';
12
13
  export * from './httpClient/HttpRequestBuilder';
13
14
  export * from './httpClient/HttpClient';
14
15
  export * from './httpClient/FetchHttpClient';
@@ -17,7 +18,7 @@ export * from './event/DynamoDBEventMapper';
17
18
  export * from './event/DomainEvent';
18
19
  export * from './event/AggregateRoot';
19
20
  export * from './date/DateManipulator';
21
+ export * from './event/EventHandler';
20
22
  export * from './config/ConfigurationLoader';
21
23
  export * from './cloudflare/ImplCloudflareKVHttpService';
22
24
  export * from './cloudflare/CloudflareKVHttpService';
23
- export * from './event/EventHandler';
package/dist/package.js CHANGED
@@ -25,6 +25,7 @@ __exportStar(require("./logger/SquizRemoteLogger"), exports);
25
25
  __exportStar(require("./logger/RemoteLogger"), exports);
26
26
  __exportStar(require("./logger/LoggerMessage"), exports);
27
27
  __exportStar(require("./logger/Logger"), exports);
28
+ __exportStar(require("./logger/LogsLambdaHandler"), exports);
28
29
  __exportStar(require("./httpClient/HttpRequestBuilder"), exports);
29
30
  __exportStar(require("./httpClient/HttpClient"), exports);
30
31
  __exportStar(require("./httpClient/FetchHttpClient"), exports);
@@ -33,8 +34,8 @@ __exportStar(require("./event/DynamoDBEventMapper"), exports);
33
34
  __exportStar(require("./event/DomainEvent"), exports);
34
35
  __exportStar(require("./event/AggregateRoot"), exports);
35
36
  __exportStar(require("./date/DateManipulator"), exports);
37
+ __exportStar(require("./event/EventHandler"), exports);
36
38
  __exportStar(require("./config/ConfigurationLoader"), exports);
37
39
  __exportStar(require("./cloudflare/ImplCloudflareKVHttpService"), exports);
38
40
  __exportStar(require("./cloudflare/CloudflareKVHttpService"), exports);
39
- __exportStar(require("./event/EventHandler"), exports);
40
41
  //# sourceMappingURL=package.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"package.js","sourceRoot":"","sources":["../src/package.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC;AACvC,gEAA8C;AAC9C,yDAAuC;AACvC,wDAAsC;AACtC,iDAA+B;AAC/B,wDAAsC;AACtC,mEAAiD;AACjD,6DAA2C;AAC3C,wDAAsC;AACtC,yDAAuC;AACvC,kDAAgC;AAChC,kEAAgD;AAChD,0DAAwC;AACxC,+DAA6C;AAC7C,8DAA4C;AAC5C,8DAA4C;AAC5C,sDAAoC;AACpC,wDAAsC;AACtC,yDAAuC;AACvC,+DAA6C;AAC7C,2EAAyD;AACzD,uEAAqD;AACrD,uDAAqC"}
1
+ {"version":3,"file":"package.js","sourceRoot":"","sources":["../src/package.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC;AAEvC,gEAA8C;AAE9C,yDAAuC;AACvC,wDAAsC;AAEtC,iDAA+B;AAE/B,wDAAsC;AACtC,mEAAiD;AAEjD,6DAA2C;AAC3C,wDAAsC;AACtC,yDAAuC;AACvC,kDAAgC;AAChC,6DAA2C;AAE3C,kEAAgD;AAChD,0DAAwC;AACxC,+DAA6C;AAE7C,8DAA4C;AAE5C,8DAA4C;AAC5C,sDAAoC;AACpC,wDAAsC;AAEtC,yDAAuC;AACvC,uDAAqC;AAErC,+DAA6C;AAE7C,2EAAyD;AACzD,uEAAqD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squiz/optimization-utils",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "",
5
5
  "main": "dist/package.js",
6
6
  "types": "dist/package.d.ts",
@@ -35,6 +35,7 @@ export const TENANT_ID_METADATA = (
35
35
  });
36
36
 
37
37
  export const PROCESSABLE_LOG_METADATA = { processable: true } as const;
38
+ export const REMOTE_LOG_METADATA = { remote: true } as const;
38
39
 
39
40
  export type LogMessage = (
40
41
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -52,6 +53,7 @@ export type CreateLog = {
52
53
  caller: InstanceType<T> | string,
53
54
  ) => CreateLog;
54
55
  isProcessable: () => CreateLog;
56
+ remote: () => CreateLog;
55
57
  getMetadata: () => Record<string, unknown>;
56
58
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
59
  create: <T extends abstract new (...args: any) => any>(
@@ -112,6 +114,10 @@ export function createLog(opts?: {
112
114
  return attachMetadata(PROCESSABLE_LOG_METADATA);
113
115
  };
114
116
 
117
+ const remote = (): CreateLog => {
118
+ return attachMetadata(REMOTE_LOG_METADATA);
119
+ };
120
+
115
121
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
116
122
  const attachCaller = <T extends abstract new (...args: any) => any>(
117
123
  caller: T | string,
@@ -146,6 +152,7 @@ export function createLog(opts?: {
146
152
  isProcessable,
147
153
  attachCaller,
148
154
  getMetadata: () => opts?.metadata ?? {},
155
+ remote,
149
156
  create,
150
157
  };
151
158
  }
@@ -0,0 +1,66 @@
1
+ import type { CloudWatchLogsEvent } from 'aws-lambda';
2
+ import zlib from 'zlib';
3
+ import { inject, injectable } from 'inversify';
4
+ import { inspect } from 'util';
5
+ import type { CloudWatchLogsLogEvent } from 'aws-lambda/trigger/cloudwatch-logs';
6
+ import { REMOTE_LOG_SCHEMA, RemoteLog, RemoteLogger } from './RemoteLogger';
7
+ import { Logger } from './Logger';
8
+ import { createLogMessage } from './LoggerMessage';
9
+
10
+ @injectable()
11
+ export class LogsHandler {
12
+ constructor(
13
+ @inject(RemoteLogger)
14
+ private readonly remoteLogger: RemoteLogger,
15
+ @inject(Logger)
16
+ private readonly logger: Logger,
17
+ ) {}
18
+
19
+ async handle(event: CloudWatchLogsEvent): Promise<void> {
20
+ const logMessage = createLogMessage(this);
21
+
22
+ this.logger.debug(logMessage(`started mapping CloudWatchLogsEvent`));
23
+ const remoteLogs = this.mapLogs(event, logMessage);
24
+
25
+ this.logger.debug(logMessage(`finished mapping CloudWatchLogsEvent`));
26
+
27
+ this.logger.debug(
28
+ logMessage(
29
+ `started sending logs (count: ${remoteLogs.length}) into the RemoteLogger`,
30
+ ),
31
+ );
32
+ await this.remoteLogger.log(remoteLogs);
33
+ this.logger.debug(
34
+ logMessage('finished sending logs into the RemoteLogger'),
35
+ );
36
+ }
37
+
38
+ private mapLogs(
39
+ event: CloudWatchLogsEvent,
40
+ logMessage: ReturnType<typeof createLogMessage>,
41
+ ): Array<RemoteLog> {
42
+ const logs = this.decodeLogs(event);
43
+
44
+ this.logger.debug(
45
+ logMessage(`received decoded logs: ${inspect(logs, { depth: 4 })}`),
46
+ );
47
+ const isRemoteLog = (log: undefined | RemoteLog): log is RemoteLog => !!log;
48
+
49
+ return logs
50
+ .map((log) => {
51
+ const result = REMOTE_LOG_SCHEMA.safeParse(JSON.parse(log.message));
52
+
53
+ return result.success ? result.data : undefined;
54
+ })
55
+ .filter(isRemoteLog);
56
+ }
57
+
58
+ private decodeLogs(
59
+ event: CloudWatchLogsEvent,
60
+ ): Array<CloudWatchLogsLogEvent> {
61
+ const payload = Buffer.from(event.awslogs.data, 'base64');
62
+ const logs = JSON.parse(zlib.unzipSync(payload).toString());
63
+
64
+ return logs.logEvents;
65
+ }
66
+ }
@@ -0,0 +1,43 @@
1
+ import { CloudWatchLogsEvent } from 'aws-lambda';
2
+ import { LogsHandler } from './LogsHandler';
3
+ import { Logger } from './Logger';
4
+ import { Container } from 'inversify';
5
+
6
+ export const CLOUDWATCH_FILTER_PATTERN = `{ $.level = "info" || $.level = "warn" || ($.level = "error" && $.processable IS TRUE) || $.remote IS TRUE }`;
7
+
8
+ export type LogsLambdaHandler = (
9
+ event: CloudWatchLogsEvent,
10
+ ) => Promise<{ status: string }>;
11
+
12
+ export function createLogsLambdaHandler(instances: {
13
+ logsHandler: LogsHandler;
14
+ logger: Logger;
15
+ }): LogsLambdaHandler;
16
+ export function createLogsLambdaHandler(
17
+ container: Container,
18
+ ): LogsLambdaHandler;
19
+ export function createLogsLambdaHandler(
20
+ opts: { logsHandler: LogsHandler; logger: Logger } | Container,
21
+ ): LogsLambdaHandler {
22
+ let logsHandler: LogsHandler;
23
+ let logger: Logger;
24
+
25
+ if (opts instanceof Container) {
26
+ logsHandler = opts.get(LogsHandler);
27
+ logger = opts.get(Logger);
28
+ } else {
29
+ logsHandler = opts.logsHandler;
30
+ logger = opts.logger;
31
+ }
32
+
33
+ return async (event: CloudWatchLogsEvent) => {
34
+ try {
35
+ await logsHandler.handle(event);
36
+
37
+ return { status: 'ok' };
38
+ } catch (e) {
39
+ logger.error(e);
40
+ throw e;
41
+ }
42
+ };
43
+ }
@@ -0,0 +1,77 @@
1
+ import { LogsHandler } from '../LogsHandler';
2
+ import zlib from 'zlib';
3
+ import { CloudWatchLogsEvent } from 'aws-lambda';
4
+ import { faker } from '@faker-js/faker';
5
+ import { CloudWatchLogsLogEvent } from 'aws-lambda/trigger/cloudwatch-logs';
6
+ import { RemoteLog, RemoteLogger, RemoteLogLevel } from '../RemoteLogger';
7
+ import { createLoggerMock, createRemoteLoggerMock } from '../../testing/mock';
8
+ import { TenantId } from '../../valueObject/TenantId';
9
+
10
+ const createCloudWatchEvent = (
11
+ logs: Array<Record<string, unknown>>,
12
+ ): CloudWatchLogsEvent => {
13
+ const cloudWatchLogsLogEvents: Array<CloudWatchLogsLogEvent> = logs.map(
14
+ (l) => {
15
+ return {
16
+ id: faker.number.bigInt().toString(),
17
+ timestamp: faker.date.past().valueOf(),
18
+ message: JSON.stringify(l),
19
+ };
20
+ },
21
+ );
22
+ const base64 = Buffer.from(
23
+ JSON.stringify({ logEvents: cloudWatchLogsLogEvents }),
24
+ );
25
+ const zipped = zlib.gzipSync(base64);
26
+
27
+ return {
28
+ awslogs: {
29
+ data: zipped.toString('base64'),
30
+ },
31
+ };
32
+ };
33
+
34
+ describe('LogsHandler', () => {
35
+ let logsHandler: LogsHandler;
36
+ let remoteLogger: RemoteLogger;
37
+ const remoteLog: Omit<RemoteLog, 'tenantId'> & {
38
+ tenantId: string;
39
+ } = {
40
+ level: faker.helpers.arrayElement(Object.values(RemoteLogLevel)),
41
+ message: faker.word.words(),
42
+ tenantId: faker.word.words(),
43
+ timestamp: faker.date.past(),
44
+ };
45
+
46
+ beforeEach(() => {
47
+ remoteLogger = createRemoteLoggerMock();
48
+
49
+ logsHandler = new LogsHandler(remoteLogger, createLoggerMock());
50
+ });
51
+
52
+ it('should decode a CloudWatchLogsEvent and send to the RemoteLogger', async () => {
53
+ await logsHandler.handle(createCloudWatchEvent([remoteLog]));
54
+
55
+ expect(remoteLogger.log).toHaveBeenCalledWith([
56
+ {
57
+ ...remoteLog,
58
+ tenantId: new TenantId(remoteLog.tenantId),
59
+ },
60
+ ]);
61
+ });
62
+
63
+ it('should decode a CloudWatchLogsEvent and send only the RemoteLogs to the RemoteLogger', async () => {
64
+ const otherLog = {
65
+ test: faker.word.words(),
66
+ };
67
+
68
+ await logsHandler.handle(createCloudWatchEvent([remoteLog, otherLog]));
69
+
70
+ expect(remoteLogger.log).toHaveBeenCalledWith([
71
+ {
72
+ ...remoteLog,
73
+ tenantId: new TenantId(remoteLog.tenantId),
74
+ },
75
+ ]);
76
+ });
77
+ });
package/src/package.ts CHANGED
@@ -1,23 +1,35 @@
1
1
  export * from './valueObject/TenantId';
2
+
2
3
  export * from './validation/handleValidation';
4
+
3
5
  export * from './typesUtils/utilities';
4
6
  export * from './typesUtils/DynamoDB';
7
+
5
8
  export * from './testing/mock';
9
+
6
10
  export * from './scheduler/Scheduler';
7
11
  export * from './scheduler/EventBridgeScheduler';
12
+
8
13
  export * from './logger/SquizRemoteLogger';
9
14
  export * from './logger/RemoteLogger';
10
15
  export * from './logger/LoggerMessage';
11
16
  export * from './logger/Logger';
17
+ export * from './logger/LogsLambdaHandler';
18
+
12
19
  export * from './httpClient/HttpRequestBuilder';
13
20
  export * from './httpClient/HttpClient';
14
21
  export * from './httpClient/FetchHttpClient';
22
+
15
23
  export * from './exception/DomainException';
24
+
16
25
  export * from './event/DynamoDBEventMapper';
17
26
  export * from './event/DomainEvent';
18
27
  export * from './event/AggregateRoot';
28
+
19
29
  export * from './date/DateManipulator';
30
+ export * from './event/EventHandler';
31
+
20
32
  export * from './config/ConfigurationLoader';
33
+
21
34
  export * from './cloudflare/ImplCloudflareKVHttpService';
22
35
  export * from './cloudflare/CloudflareKVHttpService';
23
- export * from './event/EventHandler';