Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add debugging logs control #467

Merged
merged 9 commits into from
Feb 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 25 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@ A lightweight PostgreSQL driver for Deno focused on developer experience.
[node-postgres](https://github.com/brianc/node-postgres) and
[pq](https://github.com/lib/pq).

## Example
## Documentation

The documentation is available on the `deno-postgres` website
[https://deno-postgres.com/](https://deno-postgres.com/)

Join the [Discord](https://discord.gg/HEdTCvZUSf) as well! It's a good place to
discuss bugs and features before opening issues.

## Examples

```ts
// deno run --allow-net --allow-read mod.ts
Expand Down Expand Up @@ -51,17 +59,6 @@ await client.connect();
await client.end();
```

For more examples, visit the documentation available at
[https://deno-postgres.com/](https://deno-postgres.com/)

## Documentation

The documentation is available on the deno-postgres website
[https://deno-postgres.com/](https://deno-postgres.com/)

Join the [Discord](https://discord.gg/HEdTCvZUSf) as well! It's a good place to
discuss bugs and features before opening issues.

## Contributing

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

## Breaking changes

Although `deno-postgres` is reasonably stable and robust, it is a WIP, and we're
still exploring the design. Expect some breaking changes as we reach version 1.0
and enhance the feature set. Please check the Releases for more info on breaking
changes. Please reach out if there are any undocumented breaking changes.

## Found issues?

Please
[file an issue](https://github.com/denodrivers/postgres/issues/new/choose) with
any problems with the driver in this repository's issue section. If you would
like to help, please look at the
[issues](https://github.com/denodrivers/postgres/issues) as well. You can pick
up one of them and try to implement it.

## Contributing guidelines

When contributing to the repository, make sure to:
Expand Down
62 changes: 57 additions & 5 deletions connection/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
BufWriter,
delay,
joinPath,
rgb24,
yellow,
} from "../deps.ts";
import { DeferredStack } from "../utils/deferred.ts";
Expand Down Expand Up @@ -68,6 +69,7 @@ import {
INCOMING_TLS_MESSAGES,
} from "./message_code.ts";
import { hashMd5Password } from "./auth.ts";
import { isDebugOptionEnabled } from "../debug.ts";

// Work around unstable limitation
type ConnectOptions =
Expand Down Expand Up @@ -97,7 +99,25 @@ function assertSuccessfulAuthentication(auth_message: Message) {
}

function logNotice(notice: Notice) {
console.error(`${bold(yellow(notice.severity))}: ${notice.message}`);
if (notice.severity === "INFO") {
console.info(
`[ ${bold(rgb24(notice.severity, 0xff99ff))} ] : ${notice.message}`,
);
} else if (notice.severity === "NOTICE") {
console.info(`[ ${bold(yellow(notice.severity))} ] : ${notice.message}`);
} else if (notice.severity === "WARNING") {
console.warn(
`[ ${bold(rgb24(notice.severity, 0xff9900))} ] : ${notice.message}`,
);
}
}

function logQuery(query: string) {
console.info(`[ ${bold(rgb24("QUERY", 0x00ccff))} ] : ${query}`);
}

function logResults(rows: unknown[]) {
console.info(`[ ${bold(rgb24("RESULTS", 0x00cc00))} ] :`, rows);
}

const decoder = new TextDecoder();
Expand Down Expand Up @@ -695,7 +715,14 @@ export class Connection {
break;
case INCOMING_QUERY_MESSAGES.NOTICE_WARNING: {
const notice = parseNoticeMessage(current_message);
logNotice(notice);
if (
isDebugOptionEnabled(
"notices",
this.#connection_params.controls?.debug,
)
) {
logNotice(notice);
}
result.warnings.push(notice);
break;
}
Expand Down Expand Up @@ -819,6 +846,12 @@ export class Connection {
/**
* https://www.postgresql.org/docs/14/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY
*/
async #preparedQuery(
query: Query<ResultType.ARRAY>,
): Promise<QueryArrayResult>;
async #preparedQuery(
query: Query<ResultType.OBJECT>,
): Promise<QueryObjectResult>;
async #preparedQuery<T extends ResultType>(
query: Query<T>,
): Promise<QueryResult> {
Expand Down Expand Up @@ -872,7 +905,14 @@ export class Connection {
break;
case INCOMING_QUERY_MESSAGES.NOTICE_WARNING: {
const notice = parseNoticeMessage(current_message);
logNotice(notice);
if (
isDebugOptionEnabled(
"notices",
this.#connection_params.controls?.debug,
)
) {
logNotice(notice);
}
result.warnings.push(notice);
break;
}
Expand Down Expand Up @@ -911,11 +951,23 @@ export class Connection {

await this.#queryLock.pop();
try {
if (
isDebugOptionEnabled("queries", this.#connection_params.controls?.debug)
) {
logQuery(query.text);
}
let result: QueryArrayResult | QueryObjectResult;
if (query.args.length === 0) {
return await this.#simpleQuery(query);
result = await this.#simpleQuery(query);
} else {
return await this.#preparedQuery(query);
result = await this.#preparedQuery(query);
}
if (
isDebugOptionEnabled("results", this.#connection_params.controls?.debug)
) {
logResults(result.rows);
}
return result;
} catch (e) {
if (e instanceof ConnectionError) {
await this.end();
Expand Down
5 changes: 5 additions & 0 deletions connection/connection_params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { parseConnectionUri } from "../utils/utils.ts";
import { ConnectionParamsError } from "../client/error.ts";
import { fromFileUrl, isAbsolute } from "../deps.ts";
import { OidType } from "../query/oid.ts";
import { DebugControls } from "../debug.ts";

/**
* The connection string must match the following URI structure. All parameters but database and user are optional
Expand Down Expand Up @@ -115,6 +116,10 @@ export type DecoderFunction = (value: string, oid: number) => unknown;
* Control the behavior for the client instance
*/
export type ClientControls = {
/**
* Debugging options
*/
debug?: DebugControls;
/**
* The strategy to use when decoding results data
*
Expand Down
28 changes: 28 additions & 0 deletions debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Controls debugging behavior. If set to `true`, all debug options are enabled.
* If set to `false`, all debug options are disabled. Can also be an object with
* specific debug options to enable.
*
* {@default false}
*/
export type DebugControls = DebugOptions | boolean;

type DebugOptions = {
/** Log queries */
queries?: boolean;
/** Log INFO, NOTICE, and WARNING raised database messages */
notices?: boolean;
/** Log results */
results?: boolean;
};

export const isDebugOptionEnabled = (
option: keyof DebugOptions,
options?: DebugControls,
): boolean => {
if (typeof options === "boolean") {
return options;
}

return !!options?.[option];
};
6 changes: 5 additions & 1 deletion deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ export { BufWriter } from "https://deno.land/[email protected]/io/buf_writer.ts";
export { copy } from "https://deno.land/[email protected]/bytes/copy.ts";
export { crypto } from "https://deno.land/[email protected]/crypto/crypto.ts";
export { delay } from "https://deno.land/[email protected]/async/delay.ts";
export { bold, yellow } from "https://deno.land/[email protected]/fmt/colors.ts";
export {
bold,
rgb24,
yellow,
} from "https://deno.land/[email protected]/fmt/colors.ts";
export {
fromFileUrl,
isAbsolute,
Expand Down
57 changes: 57 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1393,3 +1393,60 @@ await transaction.queryArray`INSERT INTO DONT_DELETE_ME VALUES (2)`; // Still in
await transaction.commit();
// Transaction ends, client gets unlocked
```

## Debugging

The driver can provide different types of logs if as needed. By default, logs
are disabled to keep your environment as uncluttered as possible. Logging can be
enabled by using the `debug` option in the Client `controls` parameter. Pass
`true` to enable all logs, or turn on logs granulary by enabling the following
options:

- `queries` : Logs all SQL queries executed by the client
- `notices` : Logs database messages (INFO, NOTICE, WARNING))
- `results` : Logs the result of the queries

### Example

```ts
// debug_test.ts
import { Client } from "./mod.ts";

const client = new Client({
user: "postgres",
database: "postgres",
hostname: "localhost",
port: 5432,
password: "postgres",
controls: {
// the same as `debug: true`
debug: {
queries: true,
notices: true,
results: true,
},
},
});

await client.connect();

const result = await client.queryObject`SELECT public.get_some_user()`;

await client.end();
```

```sql
-- example database function that raises messages
CREATE OR REPLACE FUNCTION public.get_uuid()
RETURNS uuid LANGUAGE plpgsql
AS $function$
BEGIN
RAISE INFO 'This function generates a random UUID :)';
RAISE NOTICE 'A UUID takes up 128 bits in memory.';
RAISE WARNING 'UUIDs must follow a specific format and lenght in order to be valid!';
RETURN gen_random_uuid();
END;
$function$;;
```

![debug-output](debug-output.png)
Binary file added docs/debug-output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading