@prosopo/api-express-router 3.1.42 → 3.1.43
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/.turbo/turbo-build$colon$cjs.log +3 -3
- package/.turbo/turbo-build$colon$tsc.log +21 -21
- package/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +45 -0
- package/dist/cjs/middlewares/requestLoggerMiddleware.cjs +33 -1
- package/dist/middlewares/requestLoggerMiddleware.d.ts.map +1 -1
- package/dist/middlewares/requestLoggerMiddleware.js +33 -1
- package/dist/middlewares/requestLoggerMiddleware.js.map +1 -1
- package/package.json +5 -5
- package/src/middlewares/requestLoggerMiddleware.ts +53 -4
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/api-express-router@3.1.
|
|
2
|
+
> @prosopo/api-express-router@3.1.43 build:cjs
|
|
3
3
|
> NODE_ENV=${NODE_ENV:-development}; vite build --config vite.cjs.config.ts --mode $NODE_ENV
|
|
4
4
|
|
|
5
5
|
ViteCommonJSConfig: .
|
|
@@ -51,8 +51,8 @@ Build end
|
|
|
51
51
|
rendering chunks...
|
|
52
52
|
[2mdist/cjs/[22m[36merrorHandler.cjs [39m[1m[2m0.49 kB[22m[1m[22m
|
|
53
53
|
[2mdist/cjs/[22m[36mapiExpressRouterFactory.cjs [39m[1m[2m0.92 kB[22m[1m[22m
|
|
54
|
-
[2mdist/cjs/[22m[36mmiddlewares/requestLoggerMiddleware.cjs [39m[1m[2m1.06 kB[22m[1m[22m
|
|
55
54
|
[2mdist/cjs/[22m[36mendpointAdapter/apiExpressDefaultEndpointAdapter.cjs [39m[1m[2m1.12 kB[22m[1m[22m
|
|
56
55
|
[2mdist/cjs/[22m[36mindex.cjs [39m[1m[2m1.16 kB[22m[1m[22m
|
|
57
56
|
[2mdist/cjs/[22m[36mmiddlewares/authMiddleware.cjs [39m[1m[2m1.86 kB[22m[1m[22m
|
|
58
|
-
[
|
|
57
|
+
[2mdist/cjs/[22m[36mmiddlewares/requestLoggerMiddleware.cjs [39m[1m[2m1.98 kB[22m[1m[22m
|
|
58
|
+
[32m✓ built in 128ms[39m
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/api-express-router@3.1.
|
|
2
|
+
> @prosopo/api-express-router@3.1.43 build:tsc
|
|
3
3
|
> tsc --build --verbose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
1:22:15 PM - Projects in this build:
|
|
6
6
|
* ../../dev/config/tsconfig.json
|
|
7
7
|
* ../util/tsconfig.json
|
|
8
8
|
* ../logger/tsconfig.json
|
|
@@ -22,41 +22,41 @@
|
|
|
22
22
|
* ../env/tsconfig.json
|
|
23
23
|
* tsconfig.json
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
1:22:15 PM - Project '../../dev/config/tsconfig.json' is up to date because newest input '../../dev/config/src/webpack/webpack.config.ts' is older than output '../../dev/config/tsconfig.tsbuildinfo'
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
1:22:15 PM - Project '../util/tsconfig.json' is up to date because newest input '../util/src/url.ts' is older than output '../util/tsconfig.tsbuildinfo'
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
1:22:15 PM - Project '../logger/tsconfig.json' is up to date because newest input '../logger/src/index.ts' is older than output '../logger/tsconfig.tsbuildinfo'
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
1:22:15 PM - Project '../api-route/tsconfig.json' is up to date because newest input '../api-route/src/apiRoutes.ts' is older than output '../api-route/tsconfig.tsbuildinfo'
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
1:22:15 PM - Project '../locale/tsconfig.json' is up to date because newest input '../locale/src/translationKey.ts' is older than output '../locale/tsconfig.tsbuildinfo'
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
1:22:15 PM - Project '../util-crypto/tsconfig.json' is up to date because newest input '../util-crypto/src/types.ts' is older than output '../util-crypto/tsconfig.tsbuildinfo'
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
1:22:15 PM - Project '../types/tsconfig.json' is up to date because newest input '../types/src/provider/api.ts' is older than output '../types/tsconfig.tsbuildinfo'
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
1:22:15 PM - Project '../common/tsconfig.json' is up to date because newest input '../common/src/index.ts' is older than output '../common/tsconfig.tsbuildinfo'
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
1:22:15 PM - Project '../ipinfo/tsconfig.json' is up to date because newest input '../ipinfo/src/index.ts' is older than output '../ipinfo/tsconfig.tsbuildinfo'
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
1:22:15 PM - Project '../redis-client/tsconfig.json' is up to date because newest input '../redis-client/src/tests/testRedisConnection.ts' is older than output '../redis-client/tsconfig.tsbuildinfo'
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
1:22:15 PM - Project '../api/tsconfig.json' is up to date because newest input '../api/src/index.ts' is older than output '../api/tsconfig.tsbuildinfo'
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
1:22:15 PM - Project '../user-access-policy/tsconfig.json' is up to date because newest input '../user-access-policy/src/transformRule.ts' is older than output '../user-access-policy/tsconfig.tsbuildinfo'
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
1:22:15 PM - Project '../types-database/tsconfig.json' is up to date because newest input '../types-database/src/types/bannedDomain.ts' is older than output '../types-database/tsconfig.tsbuildinfo'
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
1:22:15 PM - Project '../database/tsconfig.json' is up to date because newest input '../database/src/tests/mongoGlobalSetup.ts' is older than output '../database/tsconfig.tsbuildinfo'
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
1:22:15 PM - Project '../keyring/tsconfig.json' is up to date because newest input '../keyring/src/pair/decode.ts' is older than output '../keyring/tsconfig.tsbuildinfo'
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
1:22:15 PM - Project '../types-env/tsconfig.json' is up to date because newest input '../types-env/src/env.ts' is older than output '../types-env/tsconfig.tsbuildinfo'
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
1:22:15 PM - Project '../env/tsconfig.json' is up to date because newest input '../env/src/env.ts' is older than output '../env/tsconfig.tsbuildinfo'
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
1:22:15 PM - Project 'tsconfig.json' is out of date because output file 'tsconfig.tsbuildinfo' does not exist
|
|
60
60
|
|
|
61
|
-
|
|
61
|
+
1:22:15 PM - Building project '/home/runner/work/captcha/captcha/packages/api-express-router/tsconfig.json'...
|
|
62
62
|
|
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
|
-
> @prosopo/api-express-router@3.1.
|
|
2
|
+
> @prosopo/api-express-router@3.1.43 build
|
|
3
3
|
> npm run build:cross-env -- --mode ${NODE_ENV:-development}
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
> @prosopo/api-express-router@3.1.
|
|
6
|
+
> @prosopo/api-express-router@3.1.43 build:cross-env
|
|
7
7
|
> vite build --config vite.esm.config.ts --mode production
|
|
8
8
|
|
|
9
9
|
ViteEsmConfig: .
|
|
@@ -56,7 +56,7 @@ rendering chunks...
|
|
|
56
56
|
[2mdist/[22m[36merrorHandler.js [39m[1m[2m0.39 kB[22m[1m[22m
|
|
57
57
|
[2mdist/[22m[36mindex.js [39m[1m[2m0.78 kB[22m[1m[22m
|
|
58
58
|
[2mdist/[22m[36mapiExpressRouterFactory.js [39m[1m[2m0.78 kB[22m[1m[22m
|
|
59
|
-
[2mdist/[22m[36mmiddlewares/requestLoggerMiddleware.js [39m[1m[2m0.95 kB[22m[1m[22m
|
|
60
59
|
[2mdist/[22m[36mendpointAdapter/apiExpressDefaultEndpointAdapter.js [39m[1m[2m1.01 kB[22m[1m[22m
|
|
61
60
|
[2mdist/[22m[36mmiddlewares/authMiddleware.js [39m[1m[2m1.73 kB[22m[1m[22m
|
|
62
|
-
[
|
|
61
|
+
[2mdist/[22m[36mmiddlewares/requestLoggerMiddleware.js [39m[1m[2m1.86 kB[22m[1m[22m
|
|
62
|
+
[32m✓ built in 177ms[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
# @prosopo/api-express-router
|
|
2
2
|
|
|
3
|
+
## 3.1.43
|
|
4
|
+
### Patch Changes
|
|
5
|
+
|
|
6
|
+
- 6abff15: Fix request-scoped logger fields leaking across concurrent captcha requests, and give every endpoint a proper request/response envelope in OpenObserve.
|
|
7
|
+
|
|
8
|
+
Three interlocking changes:
|
|
9
|
+
|
|
10
|
+
- **`Tasks.setLogger` no longer mutates `db.logger`.** `env.getDb()` returns a
|
|
11
|
+
process-wide singleton; overwriting `db.logger` on every request meant two
|
|
12
|
+
concurrent captcha submits raced, and whichever request landed second
|
|
13
|
+
stamped its `user`/`siteKey`/`sessionId` bindings onto the *other* request's
|
|
14
|
+
DB-level log lines. In practice you'd see a `PuzzleCaptcha record updated
|
|
15
|
+
successfully` for user A's challenge tagged with user B's account and site
|
|
16
|
+
key, breaking log-based forensics. `setLogger` still updates the per-request
|
|
17
|
+
Tasks instance and its per-request manager instances (those are safe —
|
|
18
|
+
they're constructed inside the Tasks constructor) but stops mutating the
|
|
19
|
+
shared DB. Callers in `getPoWCaptchaChallenge` and `getPuzzleCaptchaChallenge`
|
|
20
|
+
now pass `req.logger` directly into `new Tasks(env, req.logger)` and drop
|
|
21
|
+
the redundant `.setLogger(req.logger)` call that followed.
|
|
22
|
+
|
|
23
|
+
- **`requestLoggerMiddleware` now emits `Request received` and `Response sent`
|
|
24
|
+
envelope lines on every route** (with `method`, `path`, `status`,
|
|
25
|
+
`durationMs`, and the request id). Previously only `/frictionless` had a
|
|
26
|
+
`res.on('finish', ...)` block, so `getPow/PuzzleCaptchaChallenge`,
|
|
27
|
+
`submitPow/PuzzleCaptchaSolution`, `verify.ts` etc. produced no envelope in
|
|
28
|
+
OO — a challenge issued by one endpoint and verified by another shared
|
|
29
|
+
nothing you could group on. Health-probe paths (`/healthz`, `/health`,
|
|
30
|
+
`/readyz`) are excluded so they don't drown the stream. The middleware
|
|
31
|
+
also now mirrors `x-request-id` back on the outbound response so callers
|
|
32
|
+
downstream of the Node process can correlate without depending on Caddy.
|
|
33
|
+
|
|
34
|
+
- **`requestId` (set on the request logger via `.with({requestId})`) is
|
|
35
|
+
promoted to a top-level `req_id` field on the emitted JSON log record.**
|
|
36
|
+
OpenObserve indexes top-level fields as their own columns, so
|
|
37
|
+
`WHERE req_id = '…'` is now cheap; previously the id only lived inside
|
|
38
|
+
`data.requestId`, which flattened to `data_requestid` in OO's ingestion
|
|
39
|
+
and had no top-level column. `data.requestId` is preserved for backwards
|
|
40
|
+
compatibility with existing dashboards. Two new unit tests in
|
|
41
|
+
`@prosopo/logger` cover the promotion and the "absent when unset" case.
|
|
42
|
+
- Updated dependencies [6abff15]
|
|
43
|
+
- @prosopo/logger@2.0.3
|
|
44
|
+
- @prosopo/api-route@2.6.52
|
|
45
|
+
- @prosopo/common@3.1.45
|
|
46
|
+
- @prosopo/env@3.6.12
|
|
47
|
+
|
|
3
48
|
## 3.1.42
|
|
4
49
|
### Patch Changes
|
|
5
50
|
|
|
@@ -8,12 +8,13 @@ const getHeaderValue = (req, headerName) => {
|
|
|
8
8
|
}
|
|
9
9
|
return void 0;
|
|
10
10
|
};
|
|
11
|
+
const HEALTH_CHECK_PATHS = /* @__PURE__ */ new Set(["/healthz", "/health", "/readyz"]);
|
|
11
12
|
function requestLoggerMiddleware(env) {
|
|
12
13
|
return (req, res, next) => {
|
|
13
14
|
const requestId = req.headers["x-request-id"] || `e-${uuid.v4()}`;
|
|
14
15
|
const user = getHeaderValue(req, "prosopo-user");
|
|
15
16
|
const siteKey = getHeaderValue(req, "prosopo-site-key");
|
|
16
|
-
const sessionId = req.body?.sessionId ? req.body.sessionId :
|
|
17
|
+
const sessionId = req.body?.sessionId ? req.body.sessionId : void 0;
|
|
17
18
|
const logger$1 = logger.getLogger(
|
|
18
19
|
logger.parseLogLevel(env.config.logLevel),
|
|
19
20
|
"provider:request"
|
|
@@ -25,6 +26,37 @@ function requestLoggerMiddleware(env) {
|
|
|
25
26
|
});
|
|
26
27
|
req.logger = logger$1;
|
|
27
28
|
req.requestId = requestId;
|
|
29
|
+
res.setHeader("x-request-id", requestId);
|
|
30
|
+
if (HEALTH_CHECK_PATHS.has(req.path)) {
|
|
31
|
+
next();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const startNs = process.hrtime.bigint();
|
|
35
|
+
logger$1.info(() => ({
|
|
36
|
+
msg: "Request received",
|
|
37
|
+
data: {
|
|
38
|
+
method: req.method,
|
|
39
|
+
path: req.path
|
|
40
|
+
}
|
|
41
|
+
}));
|
|
42
|
+
let finished = false;
|
|
43
|
+
const emitFinish = (outcome) => {
|
|
44
|
+
if (finished) return;
|
|
45
|
+
finished = true;
|
|
46
|
+
const durationMs = Number(process.hrtime.bigint() - startNs) / 1e6;
|
|
47
|
+
logger$1.info(() => ({
|
|
48
|
+
msg: "Response sent",
|
|
49
|
+
data: {
|
|
50
|
+
method: req.method,
|
|
51
|
+
path: req.path,
|
|
52
|
+
status: res.statusCode,
|
|
53
|
+
durationMs,
|
|
54
|
+
outcome
|
|
55
|
+
}
|
|
56
|
+
}));
|
|
57
|
+
};
|
|
58
|
+
res.on("finish", () => emitFinish("finish"));
|
|
59
|
+
res.on("close", () => emitFinish("close"));
|
|
28
60
|
next();
|
|
29
61
|
};
|
|
30
62
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestLoggerMiddleware.d.ts","sourceRoot":"","sources":["../../src/middlewares/requestLoggerMiddleware.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"requestLoggerMiddleware.d.ts","sourceRoot":"","sources":["../../src/middlewares/requestLoggerMiddleware.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAe/D,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,mBAAmB,SAClD,OAAO,OAAO,QAAQ,QAAQ,YAAY,UAuEvD"}
|
|
@@ -6,12 +6,13 @@ const getHeaderValue = (req, headerName) => {
|
|
|
6
6
|
}
|
|
7
7
|
return void 0;
|
|
8
8
|
};
|
|
9
|
+
const HEALTH_CHECK_PATHS = /* @__PURE__ */ new Set(["/healthz", "/health", "/readyz"]);
|
|
9
10
|
function requestLoggerMiddleware(env) {
|
|
10
11
|
return (req, res, next) => {
|
|
11
12
|
const requestId = req.headers["x-request-id"] || `e-${v4()}`;
|
|
12
13
|
const user = getHeaderValue(req, "prosopo-user");
|
|
13
14
|
const siteKey = getHeaderValue(req, "prosopo-site-key");
|
|
14
|
-
const sessionId = req.body?.sessionId ? req.body.sessionId :
|
|
15
|
+
const sessionId = req.body?.sessionId ? req.body.sessionId : void 0;
|
|
15
16
|
const logger = getLogger(
|
|
16
17
|
parseLogLevel(env.config.logLevel),
|
|
17
18
|
"provider:request"
|
|
@@ -23,6 +24,37 @@ function requestLoggerMiddleware(env) {
|
|
|
23
24
|
});
|
|
24
25
|
req.logger = logger;
|
|
25
26
|
req.requestId = requestId;
|
|
27
|
+
res.setHeader("x-request-id", requestId);
|
|
28
|
+
if (HEALTH_CHECK_PATHS.has(req.path)) {
|
|
29
|
+
next();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const startNs = process.hrtime.bigint();
|
|
33
|
+
logger.info(() => ({
|
|
34
|
+
msg: "Request received",
|
|
35
|
+
data: {
|
|
36
|
+
method: req.method,
|
|
37
|
+
path: req.path
|
|
38
|
+
}
|
|
39
|
+
}));
|
|
40
|
+
let finished = false;
|
|
41
|
+
const emitFinish = (outcome) => {
|
|
42
|
+
if (finished) return;
|
|
43
|
+
finished = true;
|
|
44
|
+
const durationMs = Number(process.hrtime.bigint() - startNs) / 1e6;
|
|
45
|
+
logger.info(() => ({
|
|
46
|
+
msg: "Response sent",
|
|
47
|
+
data: {
|
|
48
|
+
method: req.method,
|
|
49
|
+
path: req.path,
|
|
50
|
+
status: res.statusCode,
|
|
51
|
+
durationMs,
|
|
52
|
+
outcome
|
|
53
|
+
}
|
|
54
|
+
}));
|
|
55
|
+
};
|
|
56
|
+
res.on("finish", () => emitFinish("finish"));
|
|
57
|
+
res.on("close", () => emitFinish("close"));
|
|
26
58
|
next();
|
|
27
59
|
};
|
|
28
60
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestLoggerMiddleware.js","sourceRoot":"","sources":["../../src/middlewares/requestLoggerMiddleware.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE3D,OAAO,EAAE,EAAE,IAAI,MAAM,EAAE,MAAM,MAAM,CAAC;AAEpC,MAAM,cAAc,GAAG,CACtB,GAAY,EACZ,UAAkB,EACG,EAAE;IACvB,IAAI,UAAU,IAAI,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QAC1D,OAAO,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,UAAU,uBAAuB,CAAC,GAAwB;IAC/D,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"requestLoggerMiddleware.js","sourceRoot":"","sources":["../../src/middlewares/requestLoggerMiddleware.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosopo/api-express-router",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.43",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -26,10 +26,10 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@polkadot/util": "13.5.7",
|
|
29
|
-
"@prosopo/api-route": "2.6.
|
|
30
|
-
"@prosopo/common": "3.1.
|
|
31
|
-
"@prosopo/logger": "2.0.
|
|
32
|
-
"@prosopo/env": "3.6.
|
|
29
|
+
"@prosopo/api-route": "2.6.52",
|
|
30
|
+
"@prosopo/common": "3.1.45",
|
|
31
|
+
"@prosopo/logger": "2.0.3",
|
|
32
|
+
"@prosopo/env": "3.6.12",
|
|
33
33
|
"@prosopo/locale": "3.2.6",
|
|
34
34
|
"@prosopo/types": "4.9.8",
|
|
35
35
|
"@prosopo/util": "3.3.4",
|
|
@@ -27,13 +27,18 @@ const getHeaderValue = (
|
|
|
27
27
|
return undefined;
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
const HEALTH_CHECK_PATHS = new Set(["/healthz", "/health", "/readyz"]);
|
|
31
|
+
|
|
30
32
|
export function requestLoggerMiddleware(env: ProviderEnvironment) {
|
|
31
33
|
return (req: Request, res: Response, next: NextFunction) => {
|
|
34
|
+
// Honour an inbound `x-request-id` (Caddy/upstream proxy assigns one and
|
|
35
|
+
// we want the same value to link Caddy access logs to Node app logs).
|
|
36
|
+
// Fall back to `e-<uuid>` when the upstream didn't set one.
|
|
32
37
|
const requestId =
|
|
33
|
-
(req.headers["x-request-id"] as string) || `e-${uuidv4()}`;
|
|
38
|
+
(req.headers["x-request-id"] as string) || `e-${uuidv4()}`;
|
|
34
39
|
const user = getHeaderValue(req, "prosopo-user");
|
|
35
40
|
const siteKey = getHeaderValue(req, "prosopo-site-key");
|
|
36
|
-
const sessionId = req.body?.sessionId ? req.body.sessionId :
|
|
41
|
+
const sessionId = req.body?.sessionId ? req.body.sessionId : undefined;
|
|
37
42
|
|
|
38
43
|
const logger = getLogger(
|
|
39
44
|
parseLogLevel(env.config.logLevel),
|
|
@@ -45,11 +50,55 @@ export function requestLoggerMiddleware(env: ProviderEnvironment) {
|
|
|
45
50
|
...(sessionId ? { sessionId } : {}),
|
|
46
51
|
});
|
|
47
52
|
|
|
48
|
-
// Attach logger to the request
|
|
49
53
|
req.logger = logger;
|
|
50
54
|
req.requestId = requestId;
|
|
51
55
|
|
|
52
|
-
//
|
|
56
|
+
// Mirror the requestId back to the client so downstream systems can
|
|
57
|
+
// correlate their own logs to ours.
|
|
58
|
+
res.setHeader("x-request-id", requestId);
|
|
59
|
+
|
|
60
|
+
// Skip request/response envelope logging for high-volume health probes
|
|
61
|
+
// so they don't drown out useful captcha-endpoint entries.
|
|
62
|
+
if (HEALTH_CHECK_PATHS.has(req.path)) {
|
|
63
|
+
next();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Emit a single request-received line so every endpoint has an entry
|
|
68
|
+
// log in OpenObserve even when the handler itself doesn't log. Kept at
|
|
69
|
+
// info level; drop to debug if the volume becomes a problem.
|
|
70
|
+
const startNs = process.hrtime.bigint();
|
|
71
|
+
logger.info(() => ({
|
|
72
|
+
msg: "Request received",
|
|
73
|
+
data: {
|
|
74
|
+
method: req.method,
|
|
75
|
+
path: req.path,
|
|
76
|
+
},
|
|
77
|
+
}));
|
|
78
|
+
|
|
79
|
+
// Log a response-finished line. `finish` fires when the response was
|
|
80
|
+
// sent successfully; `close` fires when the client disconnects before
|
|
81
|
+
// the response was fully sent. Guard against both firing (once() would
|
|
82
|
+
// only cover a single event source).
|
|
83
|
+
let finished = false;
|
|
84
|
+
const emitFinish = (outcome: "finish" | "close") => {
|
|
85
|
+
if (finished) return;
|
|
86
|
+
finished = true;
|
|
87
|
+
const durationMs = Number(process.hrtime.bigint() - startNs) / 1e6;
|
|
88
|
+
logger.info(() => ({
|
|
89
|
+
msg: "Response sent",
|
|
90
|
+
data: {
|
|
91
|
+
method: req.method,
|
|
92
|
+
path: req.path,
|
|
93
|
+
status: res.statusCode,
|
|
94
|
+
durationMs,
|
|
95
|
+
outcome,
|
|
96
|
+
},
|
|
97
|
+
}));
|
|
98
|
+
};
|
|
99
|
+
res.on("finish", () => emitFinish("finish"));
|
|
100
|
+
res.on("close", () => emitFinish("close"));
|
|
101
|
+
|
|
53
102
|
next();
|
|
54
103
|
};
|
|
55
104
|
}
|