Skip to content
NewFrom Mongoose to SQL6 min read

Logging & Monitoring

UQL can log every query with its duration, flag slow queries, and report migration and schema activity. You set it per pool, in the pool’s options.

logger: true turns on every level through the built-in DefaultLogger, which prints colored lines to the console:

import { PgQuerierPool } from 'uql-orm/postgres';
export const pool = new PgQuerierPool(
{ connectionString: process.env.DATABASE_URL },
{
logger: true,
slowQuery: 200, // log any query taking 200ms or more as slow
},
);

An array turns on only the levels you list:

import type { ExtraOptions } from 'uql-orm';
const options: ExtraOptions = {
logger: ['error', 'warn', 'migration'],
slowQuery: 1000,
};

slowQuery works on its own: setting it logs slow queries whatever levels logger lists, even with no logger at all. The example above is a common production setup: quiet, except for problems and queries past a second.

Bound values are not logged unless you set logValues: true, since query parameters may hold personal data. It applies to query logs and slow-query logs alike.

const options: ExtraOptions = {
logger: true,
logValues: true,
};
Level What it logs
query Each statement or command, with its duration (and values if on).
error / warn Errors and warnings.
migration Each migration as it runs and finishes.
skippedMigration Destructive schema changes that sync held back in safe mode.
schema / info Schema sync steps and other events.

A dropped idle connection on a driver pool is always logged through the pool’s logger, even when the error level is not listed or logging is off. See when a connection dies while idle.

DefaultLogger writes lines like these (values appear only with logValues: true):

query: SELECT * FROM "user" WHERE "id" = $1 -- [123] [2ms]
slow query: UPDATE "post" SET "title" = $1 -- ["New Title"] [1250ms]
skipped migration: [AutoSync] Skipped 1 column drops in table 'user': old_field (drop: false. Use { drop: true } to apply).

A function receives everything. Queries arrive as (query, values, duration), other messages as (message) or (message, error):

const options: ExtraOptions = {
logger: (message, ...args) => myLogger.debug(message, ...args),
};

A Logger object gets one method per level: logQuery, logSlowQuery, logWarn, logError, logInfo, logSchema, logMigration and logSkippedMigration. Each is optional, so you can send slow queries somewhere regular ones do not go:

import type { ExtraOptions, Logger } from 'uql-orm';
const logger: Logger = {
logSlowQuery(query, values, duration) {
pagerduty.alert(`Slow query (${duration}ms): ${query}`);
},
logError(message, error) {
sentry.captureException(error ?? new Error(message));
},
};
const options: ExtraOptions = { logger, slowQuery: 500 };

To keep the console output and add alerting, extend DefaultLogger and override one method:

import { DefaultLogger } from 'uql-orm';
class AlertingLogger extends DefaultLogger {
override logSlowQuery(
query: string,
values?: readonly unknown[],
duration?: number,
) {
super.logSlowQuery(query, values, duration);
pagerduty.alert(`Slow query (${duration}ms): ${query}`);
}
}

Migrations take the same logger, logValues and slowQuery options: new Migrator(pool, { logger: true }).