@digitraffic/common 2026.5.26-1 → 2026.6.29-1
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/__test__/utils/lead-time-logging.test.d.ts +1 -0
- package/dist/__test__/utils/lead-time-logging.test.js +152 -0
- package/dist/aws/infra/canaries/database-checker.js +2 -3
- package/dist/aws/infra/stack/stack.d.ts +2 -0
- package/dist/aws/runtime/secrets/proxy-holder.d.ts +6 -1
- package/dist/aws/runtime/secrets/proxy-holder.js +6 -4
- package/dist/aws/runtime/secrets/rds-holder.d.ts +4 -1
- package/dist/aws/runtime/secrets/rds-holder.js +6 -4
- package/dist/utils/lead-time-logging.d.ts +10 -0
- package/dist/utils/lead-time-logging.js +33 -0
- package/package.json +6 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test, vi } from "vitest";
|
|
2
|
+
import { logger } from "../../aws/runtime/dt-logger-default.js";
|
|
3
|
+
import { logLeadTime, logLeadTimes } from "../../utils/lead-time-logging.js";
|
|
4
|
+
describe("lead-time-logging", () => {
|
|
5
|
+
afterEach(() => {
|
|
6
|
+
vi.restoreAllMocks();
|
|
7
|
+
});
|
|
8
|
+
test("logLeadTime logs expected payload", () => {
|
|
9
|
+
const infoSpy = vi
|
|
10
|
+
.spyOn(logger, "info")
|
|
11
|
+
.mockImplementation(() => undefined);
|
|
12
|
+
const errorSpy = vi
|
|
13
|
+
.spyOn(logger, "error")
|
|
14
|
+
.mockImplementation(() => undefined);
|
|
15
|
+
logLeadTime("lead-time", "test-target", 123);
|
|
16
|
+
expect(infoSpy).toHaveBeenCalledTimes(1);
|
|
17
|
+
expect(infoSpy).toHaveBeenCalledWith({
|
|
18
|
+
method: "LeadTimeLogging.logLeadTime",
|
|
19
|
+
customLeadTime: true,
|
|
20
|
+
customName: "lead-time",
|
|
21
|
+
customTarget: "test-target",
|
|
22
|
+
tookMs: 123,
|
|
23
|
+
});
|
|
24
|
+
expect(errorSpy).toHaveBeenCalledTimes(0);
|
|
25
|
+
});
|
|
26
|
+
test("logLeadTime merges extra fields", () => {
|
|
27
|
+
const infoSpy = vi
|
|
28
|
+
.spyOn(logger, "info")
|
|
29
|
+
.mockImplementation(() => undefined);
|
|
30
|
+
logLeadTime("mqtt-time", "mqtt", 88, {
|
|
31
|
+
customSource: "mqtt",
|
|
32
|
+
customRetriesCount: 2,
|
|
33
|
+
});
|
|
34
|
+
expect(infoSpy).toHaveBeenCalledTimes(1);
|
|
35
|
+
expect(infoSpy).toHaveBeenCalledWith({
|
|
36
|
+
method: "LeadTimeLogging.logLeadTime",
|
|
37
|
+
customLeadTime: true,
|
|
38
|
+
customName: "mqtt-time",
|
|
39
|
+
customTarget: "mqtt",
|
|
40
|
+
tookMs: 88,
|
|
41
|
+
customSource: "mqtt",
|
|
42
|
+
customRetriesCount: 2,
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
test("logLeadTime logs error if logger.info throws", () => {
|
|
46
|
+
const infoError = new Error("boom");
|
|
47
|
+
vi.spyOn(logger, "info").mockImplementation(() => {
|
|
48
|
+
throw infoError;
|
|
49
|
+
});
|
|
50
|
+
const errorSpy = vi
|
|
51
|
+
.spyOn(logger, "error")
|
|
52
|
+
.mockImplementation(() => undefined);
|
|
53
|
+
logLeadTime("process-time", "target", 10);
|
|
54
|
+
expect(errorSpy).toHaveBeenCalledTimes(1);
|
|
55
|
+
expect(errorSpy).toHaveBeenCalledWith({
|
|
56
|
+
method: "LeadTimeLogging.logLeadTime",
|
|
57
|
+
message: "Error logging lead time",
|
|
58
|
+
error: infoError,
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
test("logLeadTimes logs only lead-time when only leadTimeMs is safe", () => {
|
|
62
|
+
const infoSpy = vi
|
|
63
|
+
.spyOn(logger, "info")
|
|
64
|
+
.mockImplementation(() => undefined);
|
|
65
|
+
logLeadTimes({ target: "x", leadTimeMs: 10 });
|
|
66
|
+
expect(infoSpy).toHaveBeenCalledTimes(1);
|
|
67
|
+
expect(infoSpy).toHaveBeenNthCalledWith(1, {
|
|
68
|
+
method: "LeadTimeLogging.logLeadTime",
|
|
69
|
+
customLeadTime: true,
|
|
70
|
+
customName: "lead-time",
|
|
71
|
+
customTarget: "x",
|
|
72
|
+
tookMs: 10,
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
test("logLeadTimes logs only process-time when only processTimeMs is safe", () => {
|
|
76
|
+
const infoSpy = vi
|
|
77
|
+
.spyOn(logger, "info")
|
|
78
|
+
.mockImplementation(() => undefined);
|
|
79
|
+
logLeadTimes({ target: "x", processTimeMs: 20 });
|
|
80
|
+
expect(infoSpy).toHaveBeenCalledTimes(1);
|
|
81
|
+
expect(infoSpy).toHaveBeenNthCalledWith(1, {
|
|
82
|
+
method: "LeadTimeLogging.logLeadTime",
|
|
83
|
+
customLeadTime: true,
|
|
84
|
+
customName: "process-time",
|
|
85
|
+
customTarget: "x",
|
|
86
|
+
tookMs: 20,
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
test("logLeadTimes logs both in order with extra fields", () => {
|
|
90
|
+
const infoSpy = vi
|
|
91
|
+
.spyOn(logger, "info")
|
|
92
|
+
.mockImplementation(() => undefined);
|
|
93
|
+
const input = {
|
|
94
|
+
target: "device",
|
|
95
|
+
leadTimeMs: 11,
|
|
96
|
+
processTimeMs: 22,
|
|
97
|
+
extraFields: { customSource: "mqtt", customPartition: 3 },
|
|
98
|
+
};
|
|
99
|
+
logLeadTimes(input);
|
|
100
|
+
expect(infoSpy).toHaveBeenCalledTimes(2);
|
|
101
|
+
expect(infoSpy).toHaveBeenNthCalledWith(1, {
|
|
102
|
+
method: "LeadTimeLogging.logLeadTime",
|
|
103
|
+
customLeadTime: true,
|
|
104
|
+
customName: "lead-time",
|
|
105
|
+
customTarget: "device",
|
|
106
|
+
tookMs: 11,
|
|
107
|
+
customSource: "mqtt",
|
|
108
|
+
customPartition: 3,
|
|
109
|
+
});
|
|
110
|
+
expect(infoSpy).toHaveBeenNthCalledWith(2, {
|
|
111
|
+
method: "LeadTimeLogging.logLeadTime",
|
|
112
|
+
customLeadTime: true,
|
|
113
|
+
customName: "process-time",
|
|
114
|
+
customTarget: "device",
|
|
115
|
+
tookMs: 22,
|
|
116
|
+
customSource: "mqtt",
|
|
117
|
+
customPartition: 3,
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
test("logLeadTimes ignores non-safe values", () => {
|
|
121
|
+
const infoSpy = vi
|
|
122
|
+
.spyOn(logger, "info")
|
|
123
|
+
.mockImplementation(() => undefined);
|
|
124
|
+
logLeadTimes({
|
|
125
|
+
target: "x",
|
|
126
|
+
leadTimeMs: 1.5,
|
|
127
|
+
processTimeMs: Number.MAX_SAFE_INTEGER + 1,
|
|
128
|
+
});
|
|
129
|
+
logLeadTimes({
|
|
130
|
+
target: "x",
|
|
131
|
+
leadTimeMs: Number.NaN,
|
|
132
|
+
processTimeMs: Infinity,
|
|
133
|
+
});
|
|
134
|
+
logLeadTimes({ target: "x" });
|
|
135
|
+
expect(infoSpy).toHaveBeenCalledTimes(0);
|
|
136
|
+
});
|
|
137
|
+
test("logLeadTimes logs negative safe integer values", () => {
|
|
138
|
+
const infoSpy = vi
|
|
139
|
+
.spyOn(logger, "info")
|
|
140
|
+
.mockImplementation(() => undefined);
|
|
141
|
+
logLeadTimes({ target: "x", leadTimeMs: -5 });
|
|
142
|
+
expect(infoSpy).toHaveBeenCalledTimes(1);
|
|
143
|
+
expect(infoSpy).toHaveBeenNthCalledWith(1, {
|
|
144
|
+
method: "LeadTimeLogging.logLeadTime",
|
|
145
|
+
customLeadTime: true,
|
|
146
|
+
customName: "lead-time",
|
|
147
|
+
customTarget: "x",
|
|
148
|
+
tookMs: -5,
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
//# sourceMappingURL=lead-time-logging.test.js.map
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import synthetics from "Synthetics";
|
|
2
2
|
import { inDatabaseReadonly } from "../../../database/database.js";
|
|
3
|
-
import { getEnvVariable } from "../../../utils/utils.js";
|
|
4
3
|
import { logger } from "../../runtime/dt-logger-default.js";
|
|
5
4
|
import { ProxyHolder } from "../../runtime/secrets/proxy-holder.js";
|
|
6
5
|
import { RdsHolder } from "../../runtime/secrets/rds-holder.js";
|
|
@@ -66,10 +65,10 @@ export class DatabaseCountChecker {
|
|
|
66
65
|
synthetics.getConfiguration().withFailedCanaryMetric(true);
|
|
67
66
|
}
|
|
68
67
|
static createForProxy() {
|
|
69
|
-
return new DatabaseCountChecker(() =>
|
|
68
|
+
return new DatabaseCountChecker(() => ProxyHolder.create().setCredentials());
|
|
70
69
|
}
|
|
71
70
|
static createForRds() {
|
|
72
|
-
return new DatabaseCountChecker(() =>
|
|
71
|
+
return new DatabaseCountChecker(() => RdsHolder.create().setCredentials());
|
|
73
72
|
}
|
|
74
73
|
/**
|
|
75
74
|
* Expect that the count is 1
|
|
@@ -20,6 +20,8 @@ export interface StackConfiguration {
|
|
|
20
20
|
readonly lambdaDbSgId?: string;
|
|
21
21
|
readonly privateSubnetIds?: string[];
|
|
22
22
|
readonly availabilityZones?: string[];
|
|
23
|
+
readonly dbWriterHost?: string;
|
|
24
|
+
readonly dbReaderHost?: string;
|
|
23
25
|
readonly trafficType: TrafficType;
|
|
24
26
|
readonly production: boolean;
|
|
25
27
|
readonly stackProps: StackProps;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import type { RdsProxySecret } from "./dbsecret.js";
|
|
2
|
+
import { SecretHolder } from "./secret-holder.js";
|
|
1
3
|
/**
|
|
2
4
|
* Holds credentials for RDS Proxy access.
|
|
3
5
|
*/
|
|
4
6
|
export declare class ProxyHolder {
|
|
5
7
|
private readonly secretHolder;
|
|
6
|
-
constructor(
|
|
8
|
+
private constructor();
|
|
9
|
+
/** Creates a new instance of ProxyHolder from given SecretHolder. */
|
|
10
|
+
static create(secretHolder: SecretHolder<RdsProxySecret>): ProxyHolder;
|
|
11
|
+
/** Creates a new instance of ProxyHolder with a new default SecretHolder(using env variable SECRET_ID). */
|
|
7
12
|
static create(): ProxyHolder;
|
|
8
13
|
setCredentials(): Promise<void>;
|
|
9
14
|
}
|
|
@@ -8,11 +8,13 @@ const RDS_PROXY_SECRET_KEYS = Object.values(RdsProxySecretKey);
|
|
|
8
8
|
*/
|
|
9
9
|
export class ProxyHolder {
|
|
10
10
|
secretHolder;
|
|
11
|
-
constructor(
|
|
12
|
-
this.secretHolder =
|
|
11
|
+
constructor(secretHolder) {
|
|
12
|
+
this.secretHolder = secretHolder;
|
|
13
13
|
}
|
|
14
|
-
static create() {
|
|
15
|
-
|
|
14
|
+
static create(secretHolder) {
|
|
15
|
+
const holder = secretHolder ??
|
|
16
|
+
new SecretHolder(getEnvVariable("SECRET_ID"), "", RDS_PROXY_SECRET_KEYS);
|
|
17
|
+
return new ProxyHolder(holder);
|
|
16
18
|
}
|
|
17
19
|
async setCredentials() {
|
|
18
20
|
const secret = await this.secretHolder.get();
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
import type { RdsSecret } from "./dbsecret.js";
|
|
2
|
+
import { SecretHolder } from "./secret-holder.js";
|
|
1
3
|
/**
|
|
2
4
|
* Holds credentials for RDS access.
|
|
3
5
|
*/
|
|
4
6
|
export declare class RdsHolder {
|
|
5
7
|
private readonly secretHolder;
|
|
6
|
-
constructor(
|
|
8
|
+
private constructor();
|
|
9
|
+
static create(rdsHolder: SecretHolder<RdsSecret>): RdsHolder;
|
|
7
10
|
static create(): RdsHolder;
|
|
8
11
|
setCredentials(): Promise<void>;
|
|
9
12
|
}
|
|
@@ -8,11 +8,13 @@ const RDS_SECRET_KEYS = Object.values(RdsSecretKey);
|
|
|
8
8
|
*/
|
|
9
9
|
export class RdsHolder {
|
|
10
10
|
secretHolder;
|
|
11
|
-
constructor(
|
|
12
|
-
this.secretHolder =
|
|
11
|
+
constructor(secretHolder) {
|
|
12
|
+
this.secretHolder = secretHolder;
|
|
13
13
|
}
|
|
14
|
-
static create() {
|
|
15
|
-
|
|
14
|
+
static create(secretHolder) {
|
|
15
|
+
const holder = secretHolder ??
|
|
16
|
+
new SecretHolder(getEnvVariable("SECRET_ID"), "", RDS_SECRET_KEYS);
|
|
17
|
+
return new RdsHolder(holder);
|
|
16
18
|
}
|
|
17
19
|
async setCredentials() {
|
|
18
20
|
const secret = await this.secretHolder.get();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CustomParams } from "../aws/runtime/dt-logger.js";
|
|
2
|
+
export interface LeadTimeLogging {
|
|
3
|
+
readonly target: string;
|
|
4
|
+
readonly leadTimeMs?: number;
|
|
5
|
+
readonly processTimeMs?: number;
|
|
6
|
+
readonly extraFields?: CustomParams;
|
|
7
|
+
}
|
|
8
|
+
export type LeadTimeType = "lead-time" | "process-time" | "mqtt-time";
|
|
9
|
+
export declare function logLeadTime(name: LeadTimeType, target: string, tookMs: number, extraFields?: CustomParams): void;
|
|
10
|
+
export declare function logLeadTimes(ptl: LeadTimeLogging): void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { logger } from "../aws/runtime/dt-logger-default.js";
|
|
2
|
+
export function logLeadTime(name, target, tookMs, extraFields) {
|
|
3
|
+
const method = "LeadTimeLogging.logLeadTime";
|
|
4
|
+
try {
|
|
5
|
+
logger.info({
|
|
6
|
+
method,
|
|
7
|
+
customLeadTime: true,
|
|
8
|
+
customName: name,
|
|
9
|
+
customTarget: target,
|
|
10
|
+
tookMs,
|
|
11
|
+
...(extraFields || {}),
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
logger.error({
|
|
16
|
+
method,
|
|
17
|
+
message: "Error logging lead time",
|
|
18
|
+
error,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function isSafe(value) {
|
|
23
|
+
return Number.isSafeInteger(value);
|
|
24
|
+
}
|
|
25
|
+
export function logLeadTimes(ptl) {
|
|
26
|
+
if (isSafe(ptl.leadTimeMs)) {
|
|
27
|
+
logLeadTime("lead-time", ptl.target, ptl.leadTimeMs, ptl.extraFields);
|
|
28
|
+
}
|
|
29
|
+
if (isSafe(ptl.processTimeMs)) {
|
|
30
|
+
logLeadTime("process-time", ptl.target, ptl.processTimeMs, ptl.extraFields);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=lead-time-logging.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digitraffic/common",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.6.29-1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "",
|
|
6
6
|
"repository": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"./dist/marine/id_utils": "./dist/marine/id_utils.js",
|
|
37
37
|
"./dist/index": "./dist/index.js",
|
|
38
38
|
"./dist/utils/api-model": "./dist/utils/api-model.js",
|
|
39
|
+
"./dist/utils/lead-time-logging": "./dist/utils/lead-time-logging.js",
|
|
39
40
|
"./dist/utils/logging": "./dist/utils/logging.js",
|
|
40
41
|
"./dist/utils/base64": "./dist/utils/base64.js",
|
|
41
42
|
"./dist/utils/date-utils": "./dist/utils/date-utils.js",
|
|
@@ -125,8 +126,8 @@
|
|
|
125
126
|
"@types/geojson": "7946.0.16",
|
|
126
127
|
"@types/geojson-validation": "1.0.3",
|
|
127
128
|
"@types/madge": "5.0.3",
|
|
128
|
-
"@types/node": "
|
|
129
|
-
"@vitest/coverage-v8": "4.1.
|
|
129
|
+
"@types/node": "24.12.4",
|
|
130
|
+
"@vitest/coverage-v8": "4.1.9",
|
|
130
131
|
"aws-cdk-lib": "2.254.0",
|
|
131
132
|
"change-case": "5.4.4",
|
|
132
133
|
"constructs": "10.6.0",
|
|
@@ -142,9 +143,9 @@
|
|
|
142
143
|
"pg-query-stream": "4.14.0",
|
|
143
144
|
"rimraf": "6.1.3",
|
|
144
145
|
"sort-package-json": "3.6.1",
|
|
145
|
-
"typescript": "
|
|
146
|
+
"typescript": "5.9.3",
|
|
146
147
|
"velocityjs": "2.1.6",
|
|
147
|
-
"vitest": "4.1.
|
|
148
|
+
"vitest": "4.1.9",
|
|
148
149
|
"zod": "4.4.3"
|
|
149
150
|
},
|
|
150
151
|
"peerDependencies": {
|