Skip to content

Commit 698360d

Browse files
authored
Feat: Add debugging logs control (#467)
* feat: add debugging controls for logs * docs: format Readme file * chore: make debug control optional * chore: update docs * chore: format files * chore: update docs * chore: add color formatting and severity level notice logging. * chore: update debug docs with example * chore: update readme doc
1 parent 08320fa commit 698360d

File tree

7 files changed

+177
-18
lines changed

7 files changed

+177
-18
lines changed

README.md

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,15 @@ A lightweight PostgreSQL driver for Deno focused on developer experience.
1212
[node-postgres](https://github.com/brianc/node-postgres) and
1313
[pq](https://github.com/lib/pq).
1414

15-
## Example
15+
## Documentation
16+
17+
The documentation is available on the `deno-postgres` website
18+
[https://deno-postgres.com/](https://deno-postgres.com/)
19+
20+
Join the [Discord](https://discord.gg/HEdTCvZUSf) as well! It's a good place to
21+
discuss bugs and features before opening issues.
22+
23+
## Examples
1624

1725
```ts
1826
// deno run --allow-net --allow-read mod.ts
@@ -51,17 +59,6 @@ await client.connect();
5159
await client.end();
5260
```
5361

54-
For more examples, visit the documentation available at
55-
[https://deno-postgres.com/](https://deno-postgres.com/)
56-
57-
## Documentation
58-
59-
The documentation is available on the deno-postgres website
60-
[https://deno-postgres.com/](https://deno-postgres.com/)
61-
62-
Join the [Discord](https://discord.gg/HEdTCvZUSf) as well! It's a good place to
63-
discuss bugs and features before opening issues.
64-
6562
## Contributing
6663

6764
### Prerequisites
@@ -156,6 +153,22 @@ This situation will stabilize as `std` and `deno-postgres` approach version 1.0.
156153
| 1.17.0 | 0.15.0 | 0.17.1 | |
157154
| 1.40.0 | 0.17.2 | | Now available on JSR |
158155

156+
## Breaking changes
157+
158+
Although `deno-postgres` is reasonably stable and robust, it is a WIP, and we're
159+
still exploring the design. Expect some breaking changes as we reach version 1.0
160+
and enhance the feature set. Please check the Releases for more info on breaking
161+
changes. Please reach out if there are any undocumented breaking changes.
162+
163+
## Found issues?
164+
165+
Please
166+
[file an issue](https://github.com/denodrivers/postgres/issues/new/choose) with
167+
any problems with the driver in this repository's issue section. If you would
168+
like to help, please look at the
169+
[issues](https://github.com/denodrivers/postgres/issues) as well. You can pick
170+
up one of them and try to implement it.
171+
159172
## Contributing guidelines
160173

161174
When contributing to the repository, make sure to:

connection/connection.ts

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
BufWriter,
3333
delay,
3434
joinPath,
35+
rgb24,
3536
yellow,
3637
} from "../deps.ts";
3738
import { DeferredStack } from "../utils/deferred.ts";
@@ -68,6 +69,7 @@ import {
6869
INCOMING_TLS_MESSAGES,
6970
} from "./message_code.ts";
7071
import { hashMd5Password } from "./auth.ts";
72+
import { isDebugOptionEnabled } from "../debug.ts";
7173

7274
// Work around unstable limitation
7375
type ConnectOptions =
@@ -97,7 +99,25 @@ function assertSuccessfulAuthentication(auth_message: Message) {
9799
}
98100

99101
function logNotice(notice: Notice) {
100-
console.error(`${bold(yellow(notice.severity))}: ${notice.message}`);
102+
if (notice.severity === "INFO") {
103+
console.info(
104+
`[ ${bold(rgb24(notice.severity, 0xff99ff))} ] : ${notice.message}`,
105+
);
106+
} else if (notice.severity === "NOTICE") {
107+
console.info(`[ ${bold(yellow(notice.severity))} ] : ${notice.message}`);
108+
} else if (notice.severity === "WARNING") {
109+
console.warn(
110+
`[ ${bold(rgb24(notice.severity, 0xff9900))} ] : ${notice.message}`,
111+
);
112+
}
113+
}
114+
115+
function logQuery(query: string) {
116+
console.info(`[ ${bold(rgb24("QUERY", 0x00ccff))} ] : ${query}`);
117+
}
118+
119+
function logResults(rows: unknown[]) {
120+
console.info(`[ ${bold(rgb24("RESULTS", 0x00cc00))} ] :`, rows);
101121
}
102122

103123
const decoder = new TextDecoder();
@@ -695,7 +715,14 @@ export class Connection {
695715
break;
696716
case INCOMING_QUERY_MESSAGES.NOTICE_WARNING: {
697717
const notice = parseNoticeMessage(current_message);
698-
logNotice(notice);
718+
if (
719+
isDebugOptionEnabled(
720+
"notices",
721+
this.#connection_params.controls?.debug,
722+
)
723+
) {
724+
logNotice(notice);
725+
}
699726
result.warnings.push(notice);
700727
break;
701728
}
@@ -819,6 +846,12 @@ export class Connection {
819846
/**
820847
* https://www.postgresql.org/docs/14/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY
821848
*/
849+
async #preparedQuery(
850+
query: Query<ResultType.ARRAY>,
851+
): Promise<QueryArrayResult>;
852+
async #preparedQuery(
853+
query: Query<ResultType.OBJECT>,
854+
): Promise<QueryObjectResult>;
822855
async #preparedQuery<T extends ResultType>(
823856
query: Query<T>,
824857
): Promise<QueryResult> {
@@ -872,7 +905,14 @@ export class Connection {
872905
break;
873906
case INCOMING_QUERY_MESSAGES.NOTICE_WARNING: {
874907
const notice = parseNoticeMessage(current_message);
875-
logNotice(notice);
908+
if (
909+
isDebugOptionEnabled(
910+
"notices",
911+
this.#connection_params.controls?.debug,
912+
)
913+
) {
914+
logNotice(notice);
915+
}
876916
result.warnings.push(notice);
877917
break;
878918
}
@@ -911,11 +951,23 @@ export class Connection {
911951

912952
await this.#queryLock.pop();
913953
try {
954+
if (
955+
isDebugOptionEnabled("queries", this.#connection_params.controls?.debug)
956+
) {
957+
logQuery(query.text);
958+
}
959+
let result: QueryArrayResult | QueryObjectResult;
914960
if (query.args.length === 0) {
915-
return await this.#simpleQuery(query);
961+
result = await this.#simpleQuery(query);
916962
} else {
917-
return await this.#preparedQuery(query);
963+
result = await this.#preparedQuery(query);
964+
}
965+
if (
966+
isDebugOptionEnabled("results", this.#connection_params.controls?.debug)
967+
) {
968+
logResults(result.rows);
918969
}
970+
return result;
919971
} catch (e) {
920972
if (e instanceof ConnectionError) {
921973
await this.end();

connection/connection_params.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { parseConnectionUri } from "../utils/utils.ts";
22
import { ConnectionParamsError } from "../client/error.ts";
33
import { fromFileUrl, isAbsolute } from "../deps.ts";
44
import { OidType } from "../query/oid.ts";
5+
import { DebugControls } from "../debug.ts";
56

67
/**
78
* The connection string must match the following URI structure. All parameters but database and user are optional
@@ -115,6 +116,10 @@ export type DecoderFunction = (value: string, oid: number) => unknown;
115116
* Control the behavior for the client instance
116117
*/
117118
export type ClientControls = {
119+
/**
120+
* Debugging options
121+
*/
122+
debug?: DebugControls;
118123
/**
119124
* The strategy to use when decoding results data
120125
*

debug.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* Controls debugging behavior. If set to `true`, all debug options are enabled.
3+
* If set to `false`, all debug options are disabled. Can also be an object with
4+
* specific debug options to enable.
5+
*
6+
* {@default false}
7+
*/
8+
export type DebugControls = DebugOptions | boolean;
9+
10+
type DebugOptions = {
11+
/** Log queries */
12+
queries?: boolean;
13+
/** Log INFO, NOTICE, and WARNING raised database messages */
14+
notices?: boolean;
15+
/** Log results */
16+
results?: boolean;
17+
};
18+
19+
export const isDebugOptionEnabled = (
20+
option: keyof DebugOptions,
21+
options?: DebugControls,
22+
): boolean => {
23+
if (typeof options === "boolean") {
24+
return options;
25+
}
26+
27+
return !!options?.[option];
28+
};

deps.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ export { BufWriter } from "https://deno.land/std@0.214.0/io/buf_writer.ts";
66
export { copy } from "https://deno.land/std@0.214.0/bytes/copy.ts";
77
export { crypto } from "https://deno.land/std@0.214.0/crypto/crypto.ts";
88
export { delay } from "https://deno.land/std@0.214.0/async/delay.ts";
9-
export { bold, yellow } from "https://deno.land/std@0.214.0/fmt/colors.ts";
9+
export {
10+
bold,
11+
rgb24,
12+
yellow,
13+
} from "https://deno.land/std@0.214.0/fmt/colors.ts";
1014
export {
1115
fromFileUrl,
1216
isAbsolute,

docs/README.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,3 +1393,60 @@ await transaction.queryArray`INSERT INTO DONT_DELETE_ME VALUES (2)`; // Still in
13931393
await transaction.commit();
13941394
// Transaction ends, client gets unlocked
13951395
```
1396+
1397+
## Debugging
1398+
1399+
The driver can provide different types of logs if as needed. By default, logs
1400+
are disabled to keep your environment as uncluttered as possible. Logging can be
1401+
enabled by using the `debug` option in the Client `controls` parameter. Pass
1402+
`true` to enable all logs, or turn on logs granulary by enabling the following
1403+
options:
1404+
1405+
- `queries` : Logs all SQL queries executed by the client
1406+
- `notices` : Logs database messages (INFO, NOTICE, WARNING))
1407+
- `results` : Logs the result of the queries
1408+
1409+
### Example
1410+
1411+
```ts
1412+
// debug_test.ts
1413+
import { Client } from "./mod.ts";
1414+
1415+
const client = new Client({
1416+
user: "postgres",
1417+
database: "postgres",
1418+
hostname: "localhost",
1419+
port: 5432,
1420+
password: "postgres",
1421+
controls: {
1422+
// the same as `debug: true`
1423+
debug: {
1424+
queries: true,
1425+
notices: true,
1426+
results: true,
1427+
},
1428+
},
1429+
});
1430+
1431+
await client.connect();
1432+
1433+
const result = await client.queryObject`SELECT public.get_some_user()`;
1434+
1435+
await client.end();
1436+
```
1437+
1438+
```sql
1439+
-- example database function that raises messages
1440+
CREATE OR REPLACE FUNCTION public.get_uuid()
1441+
RETURNS uuid LANGUAGE plpgsql
1442+
AS $function$
1443+
BEGIN
1444+
RAISE INFO 'This function generates a random UUID :)';
1445+
RAISE NOTICE 'A UUID takes up 128 bits in memory.';
1446+
RAISE WARNING 'UUIDs must follow a specific format and lenght in order to be valid!';
1447+
RETURN gen_random_uuid();
1448+
END;
1449+
$function$;;
1450+
```
1451+
1452+
![debug-output](debug-output.png)

docs/debug-output.png

28 KB
Loading

0 commit comments

Comments
 (0)