@squiz/optimization-utils 2.0.1 → 2.0.3
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/dist/cloudflare/ImplCloudflareKVHttpService.d.ts +2 -2
- package/dist/cloudflare/ImplCloudflareKVHttpService.js +8 -10
- package/dist/cloudflare/ImplCloudflareKVHttpService.js.map +1 -1
- package/dist/config/ConfigurationLoader.d.ts +1 -1
- package/dist/config/ConfigurationLoader.js +3 -4
- package/dist/config/ConfigurationLoader.js.map +1 -1
- package/dist/index.d.ts +0 -11
- package/dist/index.js +0 -11
- package/dist/index.js.map +1 -1
- package/dist/scheduler/EventBridgeScheduler.d.ts +1 -1
- package/dist/scheduler/EventBridgeScheduler.js +4 -5
- package/dist/scheduler/EventBridgeScheduler.js.map +1 -1
- package/dist/testing/mock.d.ts +0 -8
- package/dist/testing/mock.js +1 -35
- package/dist/testing/mock.js.map +1 -1
- package/package.json +4 -1
- package/CHANGELOG.md +0 -37
- package/dist/exception/DomainException.d.ts +0 -18
- package/dist/exception/DomainException.js +0 -41
- package/dist/exception/DomainException.js.map +0 -1
- package/dist/httpClient/FetchHttpClient.d.ts +0 -7
- package/dist/httpClient/FetchHttpClient.js +0 -86
- package/dist/httpClient/FetchHttpClient.js.map +0 -1
- package/dist/httpClient/HttpClient.d.ts +0 -25
- package/dist/httpClient/HttpClient.js +0 -45
- package/dist/httpClient/HttpClient.js.map +0 -1
- package/dist/httpClient/HttpRequestBuilder.d.ts +0 -22
- package/dist/httpClient/HttpRequestBuilder.js +0 -126
- package/dist/httpClient/HttpRequestBuilder.js.map +0 -1
- package/dist/logger/Logger.d.ts +0 -10
- package/dist/logger/Logger.js +0 -30
- package/dist/logger/Logger.js.map +0 -1
- package/dist/logger/LoggerMessage.d.ts +0 -43
- package/dist/logger/LoggerMessage.js +0 -111
- package/dist/logger/LoggerMessage.js.map +0 -1
- package/dist/logger/LogsHandler.d.ts +0 -11
- package/dist/logger/LogsHandler.js +0 -66
- package/dist/logger/LogsHandler.js.map +0 -1
- package/dist/logger/RemoteLogger.d.ts +0 -30
- package/dist/logger/RemoteLogger.js +0 -35
- package/dist/logger/RemoteLogger.js.map +0 -1
- package/dist/logger/SquizRemoteLogger.d.ts +0 -53
- package/dist/logger/SquizRemoteLogger.js +0 -128
- package/dist/logger/SquizRemoteLogger.js.map +0 -1
- package/dist/validation/handleValidation.d.ts +0 -2
- package/dist/validation/handleValidation.js +0 -11
- package/dist/validation/handleValidation.js.map +0 -1
- package/dist/valueObject/TenantId.d.ts +0 -10
- package/dist/valueObject/TenantId.js +0 -23
- package/dist/valueObject/TenantId.js.map +0 -1
- package/src/cloudflare/CloudflareKVHttpService.ts +0 -20
- package/src/cloudflare/ImplCloudflareKVHttpService.ts +0 -128
- package/src/cloudflare/__tests__/ImplCloudflareKVHttpService.spec.ts +0 -178
- package/src/config/ConfigurationLoader.ts +0 -72
- package/src/config/__tests__/ConfigurationLoader.spec.ts +0 -62
- package/src/date/DateManipulator.ts +0 -29
- package/src/date/__tests__/DateManipulator.spec.ts +0 -64
- package/src/event/AggregateRoot.ts +0 -5
- package/src/event/DomainEvent.ts +0 -53
- package/src/event/DynamoDBEventMapper.ts +0 -75
- package/src/event/EventHandler.ts +0 -57
- package/src/event/__tests__/DynamoDBEventMapper.spec.ts +0 -121
- package/src/exception/DomainException.ts +0 -34
- package/src/httpClient/FetchHttpClient.ts +0 -92
- package/src/httpClient/HttpClient.ts +0 -46
- package/src/httpClient/HttpRequestBuilder.ts +0 -120
- package/src/httpClient/__tests__/FetchHttpClient.spec.ts +0 -146
- package/src/httpClient/__tests__/HttpClient.spec.ts +0 -52
- package/src/httpClient/__tests__/httpRequestBuilder.spec.ts +0 -75
- package/src/index.ts +0 -37
- package/src/logger/Logger.ts +0 -40
- package/src/logger/LoggerMessage.ts +0 -179
- package/src/logger/LogsHandler.ts +0 -66
- package/src/logger/RemoteLogger.ts +0 -32
- package/src/logger/SquizRemoteLogger.ts +0 -154
- package/src/logger/__tests__/LoggerMessage.spec.ts +0 -147
- package/src/logger/__tests__/LogsHandler.spec.ts +0 -77
- package/src/logger/__tests__/SquizRemoteLogger.spec.ts +0 -185
- package/src/object/__tests__/getProperty.spec.ts +0 -17
- package/src/object/getProperty.ts +0 -21
- package/src/scheduler/EventBridgeScheduler.ts +0 -173
- package/src/scheduler/Scheduler.ts +0 -32
- package/src/scheduler/__tests__/EventBridgeScheduler.spec.ts +0 -311
- package/src/testing/mock.ts +0 -62
- package/src/typesUtils/DynamoDB.ts +0 -17
- package/src/typesUtils/utilities.ts +0 -11
- package/src/validation/handleValidation.ts +0 -13
- package/src/valueObject/TenantId.ts +0 -27
- package/tsconfig.json +0 -13
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
import { RemoteLog, RemoteLogLevel, RemoteLogger } from './RemoteLogger';
|
|
3
|
-
import { TenantId } from '../valueObject/TenantId';
|
|
4
|
-
import { injectable } from 'inversify';
|
|
5
|
-
import { Logger } from './Logger';
|
|
6
|
-
import { HttpRequestBuilderFactory } from '../httpClient/HttpRequestBuilder';
|
|
7
|
-
import { HttpMethod } from '../httpClient/HttpClient';
|
|
8
|
-
import { createLog } from './LoggerMessage';
|
|
9
|
-
|
|
10
|
-
export type SquizRemoteLoggerServiceConfig = {
|
|
11
|
-
loggerServiceUrl: URL;
|
|
12
|
-
createLogsPath: string;
|
|
13
|
-
apiKey: string;
|
|
14
|
-
serviceName: string;
|
|
15
|
-
};
|
|
16
|
-
export type SquizRemoteLoggerServiceConfigProvider =
|
|
17
|
-
() => Promise<SquizRemoteLoggerServiceConfig>;
|
|
18
|
-
|
|
19
|
-
const CREATE_LOGS_REQUEST_BODY_DTO_SCHEMA = z
|
|
20
|
-
.object({
|
|
21
|
-
level: z.enum(['INFO', 'WARNING', 'ERROR']),
|
|
22
|
-
service: z.string(),
|
|
23
|
-
timestamp: z.string().datetime(),
|
|
24
|
-
host: z.string().optional(),
|
|
25
|
-
userid: z.string().optional(),
|
|
26
|
-
message: z.string().optional(),
|
|
27
|
-
tags: z.string().optional(),
|
|
28
|
-
traceid: z.string().optional(),
|
|
29
|
-
})
|
|
30
|
-
.array();
|
|
31
|
-
|
|
32
|
-
export type CreateLogsRequestBodyDto = z.infer<
|
|
33
|
-
typeof CREATE_LOGS_REQUEST_BODY_DTO_SCHEMA
|
|
34
|
-
>;
|
|
35
|
-
|
|
36
|
-
@injectable()
|
|
37
|
-
export class SquizRemoteLogger implements RemoteLogger {
|
|
38
|
-
constructor(
|
|
39
|
-
private readonly config: SquizRemoteLoggerServiceConfigProvider,
|
|
40
|
-
private readonly logger: Logger,
|
|
41
|
-
private readonly httpRequestBuilderFactory: HttpRequestBuilderFactory,
|
|
42
|
-
) {}
|
|
43
|
-
|
|
44
|
-
async info(log: Omit<RemoteLog, 'level'>): Promise<void> {
|
|
45
|
-
await this.callApi(log.tenantId, [
|
|
46
|
-
await this.mapRemoteToRequestBody({
|
|
47
|
-
...log,
|
|
48
|
-
level: RemoteLogLevel.INFO,
|
|
49
|
-
}),
|
|
50
|
-
]);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async warn(log: Omit<RemoteLog, 'level'>): Promise<void> {
|
|
54
|
-
await this.callApi(log.tenantId, [
|
|
55
|
-
await this.mapRemoteToRequestBody({
|
|
56
|
-
...log,
|
|
57
|
-
level: RemoteLogLevel.WARN,
|
|
58
|
-
}),
|
|
59
|
-
]);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async error(log: Omit<RemoteLog, 'level'>): Promise<void> {
|
|
63
|
-
await this.callApi(log.tenantId, [
|
|
64
|
-
await this.mapRemoteToRequestBody({
|
|
65
|
-
...log,
|
|
66
|
-
level: RemoteLogLevel.ERROR,
|
|
67
|
-
}),
|
|
68
|
-
]);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
async log(logs: ReadonlyArray<RemoteLog>): Promise<void> {
|
|
72
|
-
const logsGrouped = await logs.reduce(
|
|
73
|
-
async (acc, log) => {
|
|
74
|
-
const resolvedAcc = await acc;
|
|
75
|
-
const tenantLogs = resolvedAcc[log.tenantId.valueOf()];
|
|
76
|
-
const mappedLog = await this.mapRemoteToRequestBody(log);
|
|
77
|
-
const mappedLogs: CreateLogsRequestBodyDto = tenantLogs
|
|
78
|
-
? [...tenantLogs, mappedLog]
|
|
79
|
-
: [mappedLog];
|
|
80
|
-
|
|
81
|
-
return {
|
|
82
|
-
...resolvedAcc,
|
|
83
|
-
[log.tenantId.valueOf()]: mappedLogs,
|
|
84
|
-
};
|
|
85
|
-
},
|
|
86
|
-
Promise.resolve({}) as Promise<Record<string, CreateLogsRequestBodyDto>>,
|
|
87
|
-
);
|
|
88
|
-
|
|
89
|
-
const entries = Object.entries(logsGrouped);
|
|
90
|
-
const promises = entries.map(async ([tenantId, logs]) => {
|
|
91
|
-
await this.callApi(new TenantId(tenantId), logs);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
await Promise.all(promises);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private async mapRemoteToRequestBody({
|
|
98
|
-
tenantId,
|
|
99
|
-
...log
|
|
100
|
-
}: RemoteLog): Promise<CreateLogsRequestBodyDto[number]> {
|
|
101
|
-
const config = await this.config();
|
|
102
|
-
const logLevels = new Map<
|
|
103
|
-
RemoteLogLevel,
|
|
104
|
-
CreateLogsRequestBodyDto[number]['level']
|
|
105
|
-
>([
|
|
106
|
-
[RemoteLogLevel.INFO, 'INFO'],
|
|
107
|
-
[RemoteLogLevel.WARN, 'WARNING'],
|
|
108
|
-
[RemoteLogLevel.ERROR, 'ERROR'],
|
|
109
|
-
]);
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
...log,
|
|
113
|
-
timestamp: log.timestamp
|
|
114
|
-
? log.timestamp.toISOString()
|
|
115
|
-
: new Date().toISOString(),
|
|
116
|
-
level: logLevels.get(
|
|
117
|
-
log.level,
|
|
118
|
-
) as CreateLogsRequestBodyDto[number]['level'],
|
|
119
|
-
service: config.serviceName,
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
private async callApi(
|
|
124
|
-
tenantId: TenantId,
|
|
125
|
-
logs: CreateLogsRequestBodyDto,
|
|
126
|
-
): Promise<void> {
|
|
127
|
-
if (!logs.length) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const logMessage = createLog().attachTenantId(tenantId).create(this);
|
|
132
|
-
|
|
133
|
-
this.logger.debug(...logMessage(`started receiving config`));
|
|
134
|
-
const config = await this.config();
|
|
135
|
-
|
|
136
|
-
this.logger.debug(...logMessage(`finished receiving config`));
|
|
137
|
-
|
|
138
|
-
const url = new URL(
|
|
139
|
-
config.createLogsPath + `/${tenantId.valueOf()}`,
|
|
140
|
-
config.loggerServiceUrl,
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
this.logger.debug(...logMessage(`started request to: ${url.toString()}`));
|
|
144
|
-
await this.httpRequestBuilderFactory
|
|
145
|
-
.create()
|
|
146
|
-
.url(url)
|
|
147
|
-
.method(HttpMethod.POST)
|
|
148
|
-
.applicationJson()
|
|
149
|
-
.authorizationByXApiKey(config.apiKey)
|
|
150
|
-
.body(logs)
|
|
151
|
-
.sendRequest();
|
|
152
|
-
this.logger.debug(...logMessage(`finished request to: ${url.toString()}`));
|
|
153
|
-
}
|
|
154
|
-
}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'crypto';
|
|
2
|
-
import { createLog, createLogMessage } from '../LoggerMessage';
|
|
3
|
-
import { TenantId } from '../../valueObject/TenantId';
|
|
4
|
-
|
|
5
|
-
jest.mock('crypto');
|
|
6
|
-
|
|
7
|
-
describe('createLogMessage', () => {
|
|
8
|
-
class ExampleClass {}
|
|
9
|
-
|
|
10
|
-
const mockUUID = (uuid: string): jest.Mock =>
|
|
11
|
-
(randomUUID as jest.Mock).mockReturnValueOnce(uuid);
|
|
12
|
-
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
jest.resetAllMocks();
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('should create a log message with the instance of class', () => {
|
|
18
|
-
mockUUID('some-uuid');
|
|
19
|
-
|
|
20
|
-
const logMessage = createLogMessage(new ExampleClass());
|
|
21
|
-
|
|
22
|
-
expect(logMessage('example message')).toBe(
|
|
23
|
-
'[ExampleClass][Context: some-uuid] example message',
|
|
24
|
-
);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should create a log message with given metadata', () => {
|
|
28
|
-
mockUUID('some-uuid');
|
|
29
|
-
|
|
30
|
-
const logMessage = createLogMessage(
|
|
31
|
-
new ExampleClass(),
|
|
32
|
-
'secondMetadata',
|
|
33
|
-
'thirdMetadata',
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
expect(logMessage('example message')).toBe(
|
|
37
|
-
'[ExampleClass][secondMetadata][thirdMetadata][Context: some-uuid] example message',
|
|
38
|
-
);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('should create a log message without additional metadata', () => {
|
|
42
|
-
mockUUID('some-uuid');
|
|
43
|
-
|
|
44
|
-
const logMessage = createLogMessage();
|
|
45
|
-
|
|
46
|
-
expect(logMessage('example message')).toBe(
|
|
47
|
-
'[Context: some-uuid] example message',
|
|
48
|
-
);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe('createLog', () => {
|
|
53
|
-
const mockUUID: jest.Mock<
|
|
54
|
-
ReturnType<typeof randomUUID>,
|
|
55
|
-
Parameters<typeof randomUUID>
|
|
56
|
-
> = randomUUID as jest.Mock;
|
|
57
|
-
|
|
58
|
-
beforeEach(() => {
|
|
59
|
-
mockUUID.mockReset();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('should create a log message with attached tenant id as metadata', () => {
|
|
63
|
-
const logMessage = createLog().attachTenantId(new TenantId('1')).create();
|
|
64
|
-
|
|
65
|
-
const [, metadata] = logMessage('test');
|
|
66
|
-
|
|
67
|
-
expect(metadata).toEqual({ tenantId: '1' });
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should create a log message with attached processable = true as metadata', () => {
|
|
71
|
-
const logMessage = createLog().isProcessable().create();
|
|
72
|
-
|
|
73
|
-
const [, metadata] = logMessage('test');
|
|
74
|
-
|
|
75
|
-
expect(metadata).toEqual({ processable: true });
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('should create a log message with given message', () => {
|
|
79
|
-
const logMessage = createLog().isProcessable().create();
|
|
80
|
-
|
|
81
|
-
const [message] = logMessage('test');
|
|
82
|
-
|
|
83
|
-
expect(message).toContain('test');
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('should create a log message with message and caller', () => {
|
|
87
|
-
class ExampleClass {}
|
|
88
|
-
|
|
89
|
-
const logMessage = createLog().isProcessable().create(new ExampleClass());
|
|
90
|
-
|
|
91
|
-
const [message] = logMessage('test');
|
|
92
|
-
|
|
93
|
-
expect(message).toContain('test');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('should combine metadata', () => {
|
|
97
|
-
mockUUID.mockReturnValue('70c1d16a-c15f-462b-844b-c2cd379f425f');
|
|
98
|
-
|
|
99
|
-
const logMessage = createLog()
|
|
100
|
-
.attachTenantId(new TenantId('1'))
|
|
101
|
-
.isProcessable()
|
|
102
|
-
.attachMetadata({ some: 'metadata' })
|
|
103
|
-
.create('SomeCaller');
|
|
104
|
-
|
|
105
|
-
const [, metadata] = logMessage('test');
|
|
106
|
-
|
|
107
|
-
expect(metadata).toEqual({
|
|
108
|
-
tenantId: '1',
|
|
109
|
-
processable: true,
|
|
110
|
-
some: 'metadata',
|
|
111
|
-
context: '70c1d16a-c15f-462b-844b-c2cd379f425f',
|
|
112
|
-
caller: 'SomeCaller',
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
it('should take the context from the base createLog function', () => {
|
|
117
|
-
mockUUID
|
|
118
|
-
.mockReturnValueOnce('70c1d16a-c15f-462b-844b-c2cd379f425f')
|
|
119
|
-
.mockReturnValue('16ed5709-8e7f-4fcd-a4e4-73dd01a66914');
|
|
120
|
-
|
|
121
|
-
const baseLogger = createLog();
|
|
122
|
-
|
|
123
|
-
const logMessage = createLog({
|
|
124
|
-
metadata: baseLogger.getMetadata(),
|
|
125
|
-
}).create();
|
|
126
|
-
|
|
127
|
-
const [, metadata] = logMessage('test');
|
|
128
|
-
|
|
129
|
-
expect(metadata).toEqual({
|
|
130
|
-
context: '70c1d16a-c15f-462b-844b-c2cd379f425f',
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('should attach remote to the log', () => {
|
|
135
|
-
const logMessage = createLog().create();
|
|
136
|
-
|
|
137
|
-
const result = logMessage.remote(
|
|
138
|
-
'example message',
|
|
139
|
-
new TenantId('example-tenant'),
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
expect(result).toEqual([
|
|
143
|
-
'example message',
|
|
144
|
-
{ remote: true, tenantId: 'example-tenant' },
|
|
145
|
-
]);
|
|
146
|
-
});
|
|
147
|
-
});
|
|
@@ -1,77 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import { faker } from '@faker-js/faker';
|
|
2
|
-
import { createHttpClientMock, createLoggerMock } from '../../testing/mock';
|
|
3
|
-
import { Container } from 'inversify';
|
|
4
|
-
import { HttpRequestBuilderFactory } from '../../httpClient/HttpRequestBuilder';
|
|
5
|
-
import {
|
|
6
|
-
HttpClient,
|
|
7
|
-
HttpMethod,
|
|
8
|
-
HttpRequestOptions,
|
|
9
|
-
HttpResponse,
|
|
10
|
-
} from '../../httpClient/HttpClient';
|
|
11
|
-
import { Logger } from '../Logger';
|
|
12
|
-
import {
|
|
13
|
-
CreateLogsRequestBodyDto,
|
|
14
|
-
SquizRemoteLogger,
|
|
15
|
-
SquizRemoteLoggerServiceConfigProvider,
|
|
16
|
-
} from '../SquizRemoteLogger';
|
|
17
|
-
import { RemoteLogLevel, RemoteLogger } from '../RemoteLogger';
|
|
18
|
-
import { TenantId } from '../../valueObject/TenantId';
|
|
19
|
-
|
|
20
|
-
describe('SquizRemoteLogger', () => {
|
|
21
|
-
let logger: RemoteLogger;
|
|
22
|
-
let httpClient: HttpClient;
|
|
23
|
-
const config: Awaited<ReturnType<SquizRemoteLoggerServiceConfigProvider>> = {
|
|
24
|
-
loggerServiceUrl: new URL(
|
|
25
|
-
'https://develop-apps-dxp-console.dev.dxp.squiz.cloud',
|
|
26
|
-
),
|
|
27
|
-
createLogsPath: '/__dxp/us/logging',
|
|
28
|
-
apiKey: 'apiKey',
|
|
29
|
-
serviceName: 'experiment',
|
|
30
|
-
};
|
|
31
|
-
const expectedPayload = (
|
|
32
|
-
tenantId: string,
|
|
33
|
-
body: CreateLogsRequestBodyDto,
|
|
34
|
-
): HttpRequestOptions => {
|
|
35
|
-
return {
|
|
36
|
-
url: new URL(
|
|
37
|
-
`https://develop-apps-dxp-console.dev.dxp.squiz.cloud/__dxp/us/logging/${tenantId}`,
|
|
38
|
-
),
|
|
39
|
-
method: HttpMethod.POST,
|
|
40
|
-
body,
|
|
41
|
-
headers: {
|
|
42
|
-
'Content-Type': 'application/json',
|
|
43
|
-
'x-api-key': 'apiKey',
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
beforeEach(() => {
|
|
49
|
-
const container = new Container({ defaultScope: 'Singleton' });
|
|
50
|
-
|
|
51
|
-
container.bind(SquizRemoteLogger).toDynamicValue(({ container: c }) => {
|
|
52
|
-
return new SquizRemoteLogger(
|
|
53
|
-
() => Promise.resolve(config),
|
|
54
|
-
c.get(Logger),
|
|
55
|
-
c.get(HttpRequestBuilderFactory),
|
|
56
|
-
);
|
|
57
|
-
});
|
|
58
|
-
container.bind(Logger).toConstantValue(createLoggerMock());
|
|
59
|
-
container.bind(HttpRequestBuilderFactory).toSelf();
|
|
60
|
-
container.bind(HttpClient).toConstantValue(createHttpClientMock());
|
|
61
|
-
|
|
62
|
-
httpClient = container.get(HttpClient);
|
|
63
|
-
logger = container.get(SquizRemoteLogger);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe('batch logging', () => {
|
|
67
|
-
it('should send logs for particular tenant in one call', async () => {
|
|
68
|
-
jest
|
|
69
|
-
.spyOn(httpClient, 'sendRequest')
|
|
70
|
-
.mockResolvedValueOnce(new HttpResponse({ statusCode: 201, body: {} }))
|
|
71
|
-
.mockResolvedValueOnce(new HttpResponse({ statusCode: 201, body: {} }));
|
|
72
|
-
const logs = [
|
|
73
|
-
{
|
|
74
|
-
level: RemoteLogLevel.INFO,
|
|
75
|
-
message: faker.word.words(),
|
|
76
|
-
timestamp: faker.date.past(),
|
|
77
|
-
tenantId: new TenantId('1'),
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
level: RemoteLogLevel.INFO,
|
|
81
|
-
message: faker.word.words(),
|
|
82
|
-
timestamp: faker.date.past(),
|
|
83
|
-
tenantId: new TenantId('1'),
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
level: RemoteLogLevel.INFO,
|
|
87
|
-
message: faker.word.words(),
|
|
88
|
-
timestamp: faker.date.past(),
|
|
89
|
-
tenantId: new TenantId('2'),
|
|
90
|
-
},
|
|
91
|
-
] as const;
|
|
92
|
-
|
|
93
|
-
await logger.log(logs);
|
|
94
|
-
|
|
95
|
-
expect(httpClient.sendRequest).toHaveBeenCalledWith(
|
|
96
|
-
expectedPayload('1', [
|
|
97
|
-
{
|
|
98
|
-
level: 'INFO',
|
|
99
|
-
message: logs[0].message,
|
|
100
|
-
timestamp: logs[0].timestamp.toISOString(),
|
|
101
|
-
service: 'experiment',
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
level: 'INFO',
|
|
105
|
-
message: logs[1].message,
|
|
106
|
-
timestamp: logs[1].timestamp.toISOString(),
|
|
107
|
-
service: 'experiment',
|
|
108
|
-
},
|
|
109
|
-
]),
|
|
110
|
-
);
|
|
111
|
-
expect(httpClient.sendRequest).toHaveBeenCalledWith(
|
|
112
|
-
expectedPayload('2', [
|
|
113
|
-
{
|
|
114
|
-
level: 'INFO',
|
|
115
|
-
message: logs[2].message,
|
|
116
|
-
timestamp: logs[2].timestamp.toISOString(),
|
|
117
|
-
service: 'experiment',
|
|
118
|
-
},
|
|
119
|
-
]),
|
|
120
|
-
);
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
describe('simple logging', () => {
|
|
125
|
-
const log = {
|
|
126
|
-
message: faker.word.words(),
|
|
127
|
-
timestamp: faker.date.past(),
|
|
128
|
-
tenantId: new TenantId('1'),
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
beforeEach(() => {
|
|
132
|
-
jest.spyOn(httpClient, 'sendRequest').mockResolvedValueOnce(
|
|
133
|
-
new HttpResponse({
|
|
134
|
-
statusCode: 201,
|
|
135
|
-
body: {},
|
|
136
|
-
}),
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it('should send INFO log', async () => {
|
|
141
|
-
await logger.info(log);
|
|
142
|
-
|
|
143
|
-
expect(httpClient.sendRequest).toHaveBeenCalledWith(
|
|
144
|
-
expectedPayload(log.tenantId.valueOf(), [
|
|
145
|
-
{
|
|
146
|
-
message: log.message,
|
|
147
|
-
timestamp: log.timestamp.toISOString(),
|
|
148
|
-
level: 'INFO',
|
|
149
|
-
service: 'experiment',
|
|
150
|
-
},
|
|
151
|
-
]),
|
|
152
|
-
);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it('should send WARN log', async () => {
|
|
156
|
-
await logger.warn(log);
|
|
157
|
-
|
|
158
|
-
expect(httpClient.sendRequest).toHaveBeenCalledWith(
|
|
159
|
-
expectedPayload(log.tenantId.valueOf(), [
|
|
160
|
-
{
|
|
161
|
-
message: log.message,
|
|
162
|
-
timestamp: log.timestamp.toISOString(),
|
|
163
|
-
level: 'WARNING',
|
|
164
|
-
service: 'experiment',
|
|
165
|
-
},
|
|
166
|
-
]),
|
|
167
|
-
);
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('should send ERROR log', async () => {
|
|
171
|
-
await logger.error(log);
|
|
172
|
-
|
|
173
|
-
expect(httpClient.sendRequest).toHaveBeenCalledWith(
|
|
174
|
-
expectedPayload(log.tenantId.valueOf(), [
|
|
175
|
-
{
|
|
176
|
-
message: log.message,
|
|
177
|
-
timestamp: log.timestamp.toISOString(),
|
|
178
|
-
level: 'ERROR',
|
|
179
|
-
service: 'experiment',
|
|
180
|
-
},
|
|
181
|
-
]),
|
|
182
|
-
);
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { getProperty } from '../getProperty';
|
|
2
|
-
|
|
3
|
-
it('should return a passed property', () => {
|
|
4
|
-
const object = { a: [{ b: { c: 3 } }] };
|
|
5
|
-
|
|
6
|
-
const result = getProperty(object, 'a[0].b.c');
|
|
7
|
-
|
|
8
|
-
expect(result).toBe(3);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('should return undefined if property does not exist', () => {
|
|
12
|
-
const object = { a: [{ b: { c: 3 } }] };
|
|
13
|
-
|
|
14
|
-
const result = getProperty(object, 'a[0].z.c');
|
|
15
|
-
|
|
16
|
-
expect(result).toBeUndefined();
|
|
17
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export const getProperty = (
|
|
2
|
-
obj: Record<string | symbol | number, unknown>,
|
|
3
|
-
path: string,
|
|
4
|
-
defaultValue: unknown = undefined,
|
|
5
|
-
): unknown => {
|
|
6
|
-
const travel = (regexp: RegExp) =>
|
|
7
|
-
path
|
|
8
|
-
.split(regexp)
|
|
9
|
-
.filter(Boolean)
|
|
10
|
-
.reduce<unknown>(
|
|
11
|
-
(res, key) =>
|
|
12
|
-
res !== null && res !== undefined
|
|
13
|
-
? (res as Record<string, unknown>)[key]
|
|
14
|
-
: res,
|
|
15
|
-
obj,
|
|
16
|
-
);
|
|
17
|
-
|
|
18
|
-
const result = travel(/[,[\]]+?/) || travel(/[,[\].]+?/);
|
|
19
|
-
|
|
20
|
-
return result === undefined || result === obj ? defaultValue : result;
|
|
21
|
-
};
|