slonik-interceptor-query-logging 48.12.2 → 48.13.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 +4 -0
- package/README.md +12 -21
- package/dist/factories/createQueryLoggingInterceptor.d.ts +1 -1
- package/dist/factories/createQueryLoggingInterceptor.d.ts.map +1 -1
- package/dist/factories/createQueryLoggingInterceptor.js +14 -19
- package/dist/factories/createQueryLoggingInterceptor.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/utilities/getAutoExplainPayload.d.ts.map +1 -1
- package/dist/utilities/getAutoExplainPayload.js +3 -3
- package/dist/utilities/getAutoExplainPayload.js.map +1 -1
- package/dist/utilities/getAutoExplainPayload.test.js +9 -9
- package/dist/utilities/isAutoExplainJsonMessage.d.ts.map +1 -1
- package/dist/utilities/isAutoExplainJsonMessage.js +1 -1
- package/dist/utilities/isAutoExplainJsonMessage.js.map +1 -1
- package/dist/utilities/isAutoExplainJsonMessage.test.js +4 -4
- package/package.json +32 -35
- package/src/factories/createQueryLoggingInterceptor.ts +15 -22
- package/src/index.ts +1 -1
- package/src/utilities/getAutoExplainPayload.test.ts +9 -9
- package/src/utilities/getAutoExplainPayload.ts +3 -5
- package/src/utilities/isAutoExplainJsonMessage.test.ts +4 -4
- package/src/utilities/isAutoExplainJsonMessage.ts +1 -3
- package/tsconfig.json +3 -7
- package/eslint.config.js +0 -4
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -9,9 +9,7 @@ Logs [Slonik](https://github.com/gajus/slonik) queries.
|
|
|
9
9
|
## API
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
|
-
import {
|
|
13
|
-
createQueryLoggingInterceptor
|
|
14
|
-
} from 'slonik-interceptor-query-logging';
|
|
12
|
+
import { createQueryLoggingInterceptor } from "slonik-interceptor-query-logging";
|
|
15
13
|
```
|
|
16
14
|
|
|
17
15
|
```ts
|
|
@@ -30,19 +28,13 @@ type UserConfigurationType = {|
|
|
|
30
28
|
Note: You must export `ROARR_LOG=true` environment variable for logs to be printed. Refer to [Roarr](https://github.com/gajus/roarr) documentation for more information.
|
|
31
29
|
|
|
32
30
|
```ts
|
|
33
|
-
import {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const interceptors = [
|
|
41
|
-
createQueryLoggingInterceptor()
|
|
42
|
-
];
|
|
43
|
-
|
|
44
|
-
const pool = createPool('postgres://', {
|
|
45
|
-
interceptors
|
|
31
|
+
import { createPool } from "slonik";
|
|
32
|
+
import { createQueryLoggingInterceptor } from "slonik-interceptor-query-logging";
|
|
33
|
+
|
|
34
|
+
const interceptors = [createQueryLoggingInterceptor()];
|
|
35
|
+
|
|
36
|
+
const pool = createPool("postgres://", {
|
|
37
|
+
interceptors,
|
|
46
38
|
});
|
|
47
39
|
|
|
48
40
|
await connection.any(sql`
|
|
@@ -135,7 +127,7 @@ SET client_min_messages=log;
|
|
|
135
127
|
This can be configured using `afterPoolConnection` interceptor, e.g.
|
|
136
128
|
|
|
137
129
|
```ts
|
|
138
|
-
const pool = createPool(
|
|
130
|
+
const pool = createPool("postgres://localhost", {
|
|
139
131
|
interceptors: [
|
|
140
132
|
{
|
|
141
133
|
afterPoolConnection: async (connection) => {
|
|
@@ -145,11 +137,10 @@ const pool = createPool('postgres://localhost', {
|
|
|
145
137
|
await connection.query(sql`SET auto_explain.log_min_duration=0`);
|
|
146
138
|
await connection.query(sql`SET auto_explain.log_timing=true`);
|
|
147
139
|
await connection.query(sql`SET client_min_messages=log`);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
]
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
],
|
|
151
143
|
});
|
|
152
|
-
|
|
153
144
|
```
|
|
154
145
|
|
|
155
146
|
Slonik logging interceptor recognises and parses the `auto_explain` JSON message e.g.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createQueryLoggingInterceptor.d.ts","sourceRoot":"","sources":["../../src/factories/createQueryLoggingInterceptor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C;;GAEG;AACH,KAAK,qBAAqB,GAAG;IAC3B,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;
|
|
1
|
+
{"version":3,"file":"createQueryLoggingInterceptor.d.ts","sourceRoot":"","sources":["../../src/factories/createQueryLoggingInterceptor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AAE1C;;GAEG;AACH,KAAK,qBAAqB,GAAG;IAC3B,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAUF,eAAO,MAAM,6BAA6B,GACxC,oBAAoB,qBAAqB,KACxC,WAgGF,CAAC"}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
import { getAutoExplainPayload } from
|
|
2
|
-
import { isAutoExplainJsonMessage } from
|
|
3
|
-
import prettyMs from
|
|
4
|
-
import { serializeError } from
|
|
1
|
+
import { getAutoExplainPayload } from "../utilities/getAutoExplainPayload.js";
|
|
2
|
+
import { isAutoExplainJsonMessage } from "../utilities/isAutoExplainJsonMessage.js";
|
|
3
|
+
import prettyMs from "pretty-ms";
|
|
4
|
+
import { serializeError } from "serialize-error";
|
|
5
5
|
const stringifyCallSite = (callSite) => {
|
|
6
|
-
return (
|
|
7
|
-
':' +
|
|
8
|
-
callSite.lineNumber +
|
|
9
|
-
':' +
|
|
10
|
-
callSite.columnNumber);
|
|
6
|
+
return (callSite.fileName || "") + ":" + callSite.lineNumber + ":" + callSite.columnNumber;
|
|
11
7
|
};
|
|
12
8
|
const defaultConfiguration = {
|
|
13
9
|
logValues: true,
|
|
@@ -30,14 +26,13 @@ export const createQueryLoggingInterceptor = (userConfiguration) => {
|
|
|
30
26
|
if (isAutoExplainJsonMessage(notice.message)) {
|
|
31
27
|
context.log.info({
|
|
32
28
|
autoExplain: getAutoExplainPayload(notice.message),
|
|
33
|
-
},
|
|
29
|
+
}, "auto explain");
|
|
34
30
|
}
|
|
35
31
|
}
|
|
36
32
|
context.log.debug({
|
|
37
|
-
executionTime: prettyMs(Number(process.hrtime.bigint() - BigInt(context.queryInputTime)) /
|
|
38
|
-
1_000_000),
|
|
33
|
+
executionTime: prettyMs(Number(process.hrtime.bigint() - BigInt(context.queryInputTime)) / 1_000_000),
|
|
39
34
|
rowCount,
|
|
40
|
-
},
|
|
35
|
+
}, "query execution result");
|
|
41
36
|
return null;
|
|
42
37
|
},
|
|
43
38
|
beforeQueryExecution: async (context, query) => {
|
|
@@ -47,8 +42,8 @@ export const createQueryLoggingInterceptor = (userConfiguration) => {
|
|
|
47
42
|
for (const callSite of context.stackTrace) {
|
|
48
43
|
// Hide the internal call sites.
|
|
49
44
|
if (callSite.fileName !== null &&
|
|
50
|
-
!callSite.fileName.includes(
|
|
51
|
-
!callSite.fileName.includes(
|
|
45
|
+
!callSite.fileName.includes("node_modules/slonik/") &&
|
|
46
|
+
!callSite.fileName.includes("next_tick")) {
|
|
52
47
|
stackTrace.push(stringifyCallSite(callSite));
|
|
53
48
|
}
|
|
54
49
|
}
|
|
@@ -58,7 +53,7 @@ export const createQueryLoggingInterceptor = (userConfiguration) => {
|
|
|
58
53
|
values = [];
|
|
59
54
|
for (const value of query.values) {
|
|
60
55
|
if (Buffer.isBuffer(value)) {
|
|
61
|
-
values.push(
|
|
56
|
+
values.push("[Buffer " + value.byteLength + "]");
|
|
62
57
|
}
|
|
63
58
|
else {
|
|
64
59
|
values.push(value);
|
|
@@ -69,14 +64,14 @@ export const createQueryLoggingInterceptor = (userConfiguration) => {
|
|
|
69
64
|
sql: query.sql,
|
|
70
65
|
stackTrace,
|
|
71
66
|
values,
|
|
72
|
-
},
|
|
67
|
+
}, "executing query");
|
|
73
68
|
return null;
|
|
74
69
|
},
|
|
75
|
-
name:
|
|
70
|
+
name: "slonik-interceptor-query-logging",
|
|
76
71
|
queryExecutionError: (context, query, error) => {
|
|
77
72
|
context.log.error({
|
|
78
73
|
error: serializeError(error),
|
|
79
|
-
},
|
|
74
|
+
}, "query execution produced an error");
|
|
80
75
|
return null;
|
|
81
76
|
},
|
|
82
77
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createQueryLoggingInterceptor.js","sourceRoot":"","sources":["../../src/factories/createQueryLoggingInterceptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,uCAAuC,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,0CAA0C,CAAC;AACpF,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAUjD,MAAM,iBAAiB,GAAG,CAAC,QAAQ,EAAE,EAAE;IACrC,OAAO,
|
|
1
|
+
{"version":3,"file":"createQueryLoggingInterceptor.js","sourceRoot":"","sources":["../../src/factories/createQueryLoggingInterceptor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { createQueryLoggingInterceptor } from
|
|
1
|
+
export { createQueryLoggingInterceptor } from "./factories/createQueryLoggingInterceptor.js";
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { createQueryLoggingInterceptor } from
|
|
1
|
+
export { createQueryLoggingInterceptor } from "./factories/createQueryLoggingInterceptor.js";
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getAutoExplainPayload.d.ts","sourceRoot":"","sources":["../../src/utilities/getAutoExplainPayload.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,qBAAqB,GAAI,eAAe,MAAM,
|
|
1
|
+
{"version":3,"file":"getAutoExplainPayload.d.ts","sourceRoot":"","sources":["../../src/utilities/getAutoExplainPayload.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,qBAAqB,GAAI,eAAe,MAAM,QAY1D,CAAC"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { extractJson } from
|
|
1
|
+
import { extractJson } from "crack-json";
|
|
2
2
|
export const getAutoExplainPayload = (noticeMessage) => {
|
|
3
3
|
const matches = extractJson(noticeMessage);
|
|
4
4
|
if (matches.length === 0) {
|
|
5
|
-
throw new Error(
|
|
5
|
+
throw new Error("Notice message does not contain a recognizable JSON payload.");
|
|
6
6
|
}
|
|
7
7
|
if (matches.length > 1) {
|
|
8
|
-
throw new Error(
|
|
8
|
+
throw new Error("Notice message contains multiple JSON payloads.");
|
|
9
9
|
}
|
|
10
10
|
return matches[0];
|
|
11
11
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getAutoExplainPayload.js","sourceRoot":"","sources":["../../src/utilities/getAutoExplainPayload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,aAAqB,EAAE,EAAE;IAC7D,MAAM,OAAO,GAAG,WAAW,CAAC,aAAa,CAAC,CAAC;IAE3C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,
|
|
1
|
+
{"version":3,"file":"getAutoExplainPayload.js","sourceRoot":"","sources":["../../src/utilities/getAutoExplainPayload.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,aAAqB,EAAE,EAAE;IAC7D,MAAM,OAAO,GAAG,WAAW,CAAC,aAAa,CAAC,CAAC;IAE3C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAC;IAClF,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC"}
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { getAutoExplainPayload } from
|
|
2
|
-
import test from
|
|
3
|
-
test(
|
|
1
|
+
import { getAutoExplainPayload } from "./getAutoExplainPayload.js";
|
|
2
|
+
import test from "ava";
|
|
3
|
+
test("extracts JSON from the message", (t) => {
|
|
4
4
|
t.deepEqual(getAutoExplainPayload('duration: {"foo":"bar"}'), {
|
|
5
|
-
foo:
|
|
5
|
+
foo: "bar",
|
|
6
6
|
});
|
|
7
7
|
});
|
|
8
|
-
test(
|
|
8
|
+
test("throws an error if payload is not found", (t) => {
|
|
9
9
|
t.throws(() => {
|
|
10
|
-
getAutoExplainPayload(
|
|
10
|
+
getAutoExplainPayload("duration:");
|
|
11
11
|
}, {
|
|
12
|
-
message:
|
|
12
|
+
message: "Notice message does not contain a recognizable JSON payload.",
|
|
13
13
|
});
|
|
14
14
|
});
|
|
15
|
-
test(
|
|
15
|
+
test("throws an error if multiple payloads are found", (t) => {
|
|
16
16
|
t.throws(() => {
|
|
17
17
|
getAutoExplainPayload('duration: {"foo":"bar"} {"foo":"bar"}');
|
|
18
18
|
}, {
|
|
19
|
-
message:
|
|
19
|
+
message: "Notice message contains multiple JSON payloads.",
|
|
20
20
|
});
|
|
21
21
|
});
|
|
22
22
|
//# sourceMappingURL=getAutoExplainPayload.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isAutoExplainJsonMessage.d.ts","sourceRoot":"","sources":["../../src/utilities/isAutoExplainJsonMessage.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,wBAAwB,GAAI,eAAe,MAAM,KAAG,
|
|
1
|
+
{"version":3,"file":"isAutoExplainJsonMessage.d.ts","sourceRoot":"","sources":["../../src/utilities/isAutoExplainJsonMessage.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,wBAAwB,GAAI,eAAe,MAAM,KAAG,OAEhE,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export const isAutoExplainJsonMessage = (noticeMessage) => {
|
|
2
|
-
return
|
|
2
|
+
return noticeMessage.trim().startsWith("duration:") && noticeMessage.includes("{");
|
|
3
3
|
};
|
|
4
4
|
//# sourceMappingURL=isAutoExplainJsonMessage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isAutoExplainJsonMessage.js","sourceRoot":"","sources":["../../src/utilities/isAutoExplainJsonMessage.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,aAAqB,EAAW,EAAE;IACzE,OAAO,
|
|
1
|
+
{"version":3,"file":"isAutoExplainJsonMessage.js","sourceRoot":"","sources":["../../src/utilities/isAutoExplainJsonMessage.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,aAAqB,EAAW,EAAE;IACzE,OAAO,aAAa,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACrF,CAAC,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { isAutoExplainJsonMessage } from
|
|
2
|
-
import test from
|
|
3
|
-
test(
|
|
4
|
-
t.true(isAutoExplainJsonMessage(
|
|
1
|
+
import { isAutoExplainJsonMessage } from "./isAutoExplainJsonMessage.js";
|
|
2
|
+
import test from "ava";
|
|
3
|
+
test("recognizes notice containing JSON", (t) => {
|
|
4
|
+
t.true(isAutoExplainJsonMessage("duration: {}"));
|
|
5
5
|
});
|
|
6
6
|
//# sourceMappingURL=isAutoExplainJsonMessage.test.js.map
|
package/package.json
CHANGED
|
@@ -1,59 +1,56 @@
|
|
|
1
1
|
{
|
|
2
|
+
"name": "slonik-interceptor-query-logging",
|
|
3
|
+
"version": "48.13.0",
|
|
4
|
+
"description": "Logs Slonik queries.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"interceptor",
|
|
7
|
+
"logging",
|
|
8
|
+
"postgresql"
|
|
9
|
+
],
|
|
10
|
+
"license": "BSD-3-Clause",
|
|
2
11
|
"author": {
|
|
3
|
-
"email": "gajus@gajus.com",
|
|
4
12
|
"name": "Gajus Kuizinas",
|
|
13
|
+
"email": "gajus@gajus.com",
|
|
5
14
|
"url": "http://gajus.com"
|
|
6
15
|
},
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
],
|
|
11
|
-
"files": [
|
|
12
|
-
"src/**/*.test.ts"
|
|
13
|
-
],
|
|
14
|
-
"nodeArguments": [
|
|
15
|
-
"--import=tsimp"
|
|
16
|
-
]
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/gajus/slonik"
|
|
17
19
|
},
|
|
20
|
+
"type": "module",
|
|
21
|
+
"main": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
18
23
|
"dependencies": {
|
|
19
24
|
"crack-json": "^1.3.0",
|
|
20
25
|
"pretty-ms": "^9.3.0",
|
|
21
26
|
"serialize-error": "^12.0.0"
|
|
22
27
|
},
|
|
23
|
-
"description": "Logs Slonik queries.",
|
|
24
28
|
"devDependencies": {
|
|
25
29
|
"ava": "^6.4.1",
|
|
26
|
-
"
|
|
27
|
-
"slonik": "^48.12.2",
|
|
30
|
+
"slonik": "^48.13.0",
|
|
28
31
|
"tsimp": "^2.0.12",
|
|
29
|
-
"typescript": "^5.9.3"
|
|
30
|
-
"typescript-eslint": "^8.55.0",
|
|
31
|
-
"@slonik/eslint-config": "^48.12.2"
|
|
32
|
-
},
|
|
33
|
-
"engines": {
|
|
34
|
-
"node": ">=24"
|
|
32
|
+
"typescript": "^5.9.3"
|
|
35
33
|
},
|
|
36
|
-
"keywords": [
|
|
37
|
-
"postgresql",
|
|
38
|
-
"interceptor",
|
|
39
|
-
"logging"
|
|
40
|
-
],
|
|
41
|
-
"license": "BSD-3-Clause",
|
|
42
|
-
"main": "./dist/index.js",
|
|
43
|
-
"name": "slonik-interceptor-query-logging",
|
|
44
34
|
"peerDependencies": {
|
|
45
35
|
"slonik": ">=45.0.0"
|
|
46
36
|
},
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
|
|
37
|
+
"ava": {
|
|
38
|
+
"extensions": [
|
|
39
|
+
"ts"
|
|
40
|
+
],
|
|
41
|
+
"files": [
|
|
42
|
+
"src/**/*.test.ts"
|
|
43
|
+
],
|
|
44
|
+
"nodeArguments": [
|
|
45
|
+
"--import=tsimp"
|
|
46
|
+
]
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=24"
|
|
50
50
|
},
|
|
51
|
-
"type": "module",
|
|
52
|
-
"types": "./dist/index.d.ts",
|
|
53
|
-
"version": "48.12.2",
|
|
54
51
|
"scripts": {
|
|
55
52
|
"build": "rm -fr ./dist && tsc",
|
|
56
|
-
"lint": "
|
|
53
|
+
"lint": "tsc --noEmit",
|
|
57
54
|
"test": "ava --verbose --serial"
|
|
58
55
|
}
|
|
59
56
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { getAutoExplainPayload } from
|
|
2
|
-
import { isAutoExplainJsonMessage } from
|
|
3
|
-
import prettyMs from
|
|
4
|
-
import { serializeError } from
|
|
5
|
-
import type { Interceptor } from
|
|
1
|
+
import { getAutoExplainPayload } from "../utilities/getAutoExplainPayload.js";
|
|
2
|
+
import { isAutoExplainJsonMessage } from "../utilities/isAutoExplainJsonMessage.js";
|
|
3
|
+
import prettyMs from "pretty-ms";
|
|
4
|
+
import { serializeError } from "serialize-error";
|
|
5
|
+
import type { Interceptor } from "slonik";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @property logValues Dictates whether to include parameter values used to execute the query. (default: true)
|
|
@@ -12,13 +12,7 @@ type UserConfigurationType = {
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
const stringifyCallSite = (callSite) => {
|
|
15
|
-
return (
|
|
16
|
-
(callSite.fileName || '') +
|
|
17
|
-
':' +
|
|
18
|
-
callSite.lineNumber +
|
|
19
|
-
':' +
|
|
20
|
-
callSite.columnNumber
|
|
21
|
-
);
|
|
15
|
+
return (callSite.fileName || "") + ":" + callSite.lineNumber + ":" + callSite.columnNumber;
|
|
22
16
|
};
|
|
23
17
|
|
|
24
18
|
const defaultConfiguration = {
|
|
@@ -51,7 +45,7 @@ export const createQueryLoggingInterceptor = (
|
|
|
51
45
|
{
|
|
52
46
|
autoExplain: getAutoExplainPayload(notice.message),
|
|
53
47
|
},
|
|
54
|
-
|
|
48
|
+
"auto explain",
|
|
55
49
|
);
|
|
56
50
|
}
|
|
57
51
|
}
|
|
@@ -59,12 +53,11 @@ export const createQueryLoggingInterceptor = (
|
|
|
59
53
|
context.log.debug(
|
|
60
54
|
{
|
|
61
55
|
executionTime: prettyMs(
|
|
62
|
-
Number(process.hrtime.bigint() - BigInt(context.queryInputTime)) /
|
|
63
|
-
1_000_000,
|
|
56
|
+
Number(process.hrtime.bigint() - BigInt(context.queryInputTime)) / 1_000_000,
|
|
64
57
|
),
|
|
65
58
|
rowCount,
|
|
66
59
|
},
|
|
67
|
-
|
|
60
|
+
"query execution result",
|
|
68
61
|
);
|
|
69
62
|
|
|
70
63
|
return null;
|
|
@@ -79,8 +72,8 @@ export const createQueryLoggingInterceptor = (
|
|
|
79
72
|
// Hide the internal call sites.
|
|
80
73
|
if (
|
|
81
74
|
callSite.fileName !== null &&
|
|
82
|
-
!callSite.fileName.includes(
|
|
83
|
-
!callSite.fileName.includes(
|
|
75
|
+
!callSite.fileName.includes("node_modules/slonik/") &&
|
|
76
|
+
!callSite.fileName.includes("next_tick")
|
|
84
77
|
) {
|
|
85
78
|
stackTrace.push(stringifyCallSite(callSite));
|
|
86
79
|
}
|
|
@@ -94,7 +87,7 @@ export const createQueryLoggingInterceptor = (
|
|
|
94
87
|
|
|
95
88
|
for (const value of query.values) {
|
|
96
89
|
if (Buffer.isBuffer(value)) {
|
|
97
|
-
values.push(
|
|
90
|
+
values.push("[Buffer " + value.byteLength + "]");
|
|
98
91
|
} else {
|
|
99
92
|
values.push(value);
|
|
100
93
|
}
|
|
@@ -107,18 +100,18 @@ export const createQueryLoggingInterceptor = (
|
|
|
107
100
|
stackTrace,
|
|
108
101
|
values,
|
|
109
102
|
},
|
|
110
|
-
|
|
103
|
+
"executing query",
|
|
111
104
|
);
|
|
112
105
|
|
|
113
106
|
return null;
|
|
114
107
|
},
|
|
115
|
-
name:
|
|
108
|
+
name: "slonik-interceptor-query-logging",
|
|
116
109
|
queryExecutionError: (context, query, error) => {
|
|
117
110
|
context.log.error(
|
|
118
111
|
{
|
|
119
112
|
error: serializeError(error),
|
|
120
113
|
},
|
|
121
|
-
|
|
114
|
+
"query execution produced an error",
|
|
122
115
|
);
|
|
123
116
|
|
|
124
117
|
return null;
|
package/src/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { createQueryLoggingInterceptor } from
|
|
1
|
+
export { createQueryLoggingInterceptor } from "./factories/createQueryLoggingInterceptor.js";
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { getAutoExplainPayload } from
|
|
2
|
-
import test from
|
|
1
|
+
import { getAutoExplainPayload } from "./getAutoExplainPayload.js";
|
|
2
|
+
import test from "ava";
|
|
3
3
|
|
|
4
|
-
test(
|
|
4
|
+
test("extracts JSON from the message", (t) => {
|
|
5
5
|
t.deepEqual(getAutoExplainPayload('duration: {"foo":"bar"}'), {
|
|
6
|
-
foo:
|
|
6
|
+
foo: "bar",
|
|
7
7
|
});
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
-
test(
|
|
10
|
+
test("throws an error if payload is not found", (t) => {
|
|
11
11
|
t.throws(
|
|
12
12
|
() => {
|
|
13
|
-
getAutoExplainPayload(
|
|
13
|
+
getAutoExplainPayload("duration:");
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
|
-
message:
|
|
16
|
+
message: "Notice message does not contain a recognizable JSON payload.",
|
|
17
17
|
},
|
|
18
18
|
);
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
test(
|
|
21
|
+
test("throws an error if multiple payloads are found", (t) => {
|
|
22
22
|
t.throws(
|
|
23
23
|
() => {
|
|
24
24
|
getAutoExplainPayload('duration: {"foo":"bar"} {"foo":"bar"}');
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
|
-
message:
|
|
27
|
+
message: "Notice message contains multiple JSON payloads.",
|
|
28
28
|
},
|
|
29
29
|
);
|
|
30
30
|
});
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import { extractJson } from
|
|
1
|
+
import { extractJson } from "crack-json";
|
|
2
2
|
|
|
3
3
|
export const getAutoExplainPayload = (noticeMessage: string) => {
|
|
4
4
|
const matches = extractJson(noticeMessage);
|
|
5
5
|
|
|
6
6
|
if (matches.length === 0) {
|
|
7
|
-
throw new Error(
|
|
8
|
-
'Notice message does not contain a recognizable JSON payload.',
|
|
9
|
-
);
|
|
7
|
+
throw new Error("Notice message does not contain a recognizable JSON payload.");
|
|
10
8
|
}
|
|
11
9
|
|
|
12
10
|
if (matches.length > 1) {
|
|
13
|
-
throw new Error(
|
|
11
|
+
throw new Error("Notice message contains multiple JSON payloads.");
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
return matches[0];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { isAutoExplainJsonMessage } from
|
|
2
|
-
import test from
|
|
1
|
+
import { isAutoExplainJsonMessage } from "./isAutoExplainJsonMessage.js";
|
|
2
|
+
import test from "ava";
|
|
3
3
|
|
|
4
|
-
test(
|
|
5
|
-
t.true(isAutoExplainJsonMessage(
|
|
4
|
+
test("recognizes notice containing JSON", (t) => {
|
|
5
|
+
t.true(isAutoExplainJsonMessage("duration: {}"));
|
|
6
6
|
});
|
package/tsconfig.json
CHANGED
|
@@ -4,9 +4,7 @@
|
|
|
4
4
|
"declaration": true,
|
|
5
5
|
"declarationMap": true,
|
|
6
6
|
"esModuleInterop": true,
|
|
7
|
-
"lib": [
|
|
8
|
-
"es2024"
|
|
9
|
-
],
|
|
7
|
+
"lib": ["es2024"],
|
|
10
8
|
"module": "ES2022",
|
|
11
9
|
"moduleResolution": "node",
|
|
12
10
|
"noImplicitAny": false,
|
|
@@ -18,7 +16,5 @@
|
|
|
18
16
|
"target": "es2024",
|
|
19
17
|
"useUnknownInCatchVariables": false
|
|
20
18
|
},
|
|
21
|
-
"include": [
|
|
22
|
-
|
|
23
|
-
]
|
|
24
|
-
}
|
|
19
|
+
"include": ["src"]
|
|
20
|
+
}
|
package/eslint.config.js
DELETED