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.
Configuration
Section titled “Configuration”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
Section titled “Bound values”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,};Log levels
Section titled “Log levels”| 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. |
skipped |
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.
Output format
Section titled “Output format”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).Custom logger
Section titled “Custom logger”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 }).