@digitalwalletcorp/pg-pooling 0.1.0 → 0.2.1

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/README.md CHANGED
@@ -11,7 +11,8 @@ Designed for both server-side Node.js applications and cron-style background job
11
11
  * **Safe Acquire/Release**: Each checked-out client gets its own error listener and a leak-detection timer, so a forgotten `release()` is surfaced instead of silently exhausting the pool.
12
12
  * **Pool Exhaustion Diagnostics**: Warns on slow acquires (`POOL ACQUIRE SLOW`), failed acquires (`POOL CONNECT FAILED`) and suspected leaks (`POOL LEAK SUSPECT`).
13
13
  * **Transaction Helpers**: `begin()` / `commit()` / `rollback()` convenience methods.
14
- * **Optional SQL Logging**: Emits the executed SQL and a truncated result set to `console.debug` when `debug` is enabled.
14
+ * **Pluggable Logging**: Pass your own logger (`debug` / `info` / `warn` / `error`) to route logs into your application's logging. Without one, SQL logs go to the console when `debug` is enabled and warnings go through `process.emitWarning`.
15
+ * **Configurable Thresholds**: The slow-acquire and leak-suspect thresholds can be tuned or disabled.
15
16
  * **DATE Type Parsing**: PostgreSQL `DATE` (OID 1082) is returned as a `YYYY-MM-DD` string instead of a timezone-dependent `Date`.
16
17
 
17
18
  #### 📦 Installation
@@ -66,6 +67,7 @@ The application reads its own environment variables and builds the `config` (inc
66
67
  `@/server/singleton/connection-pooling`
67
68
  ```typescript
68
69
  import { PgPool } from '@digitalwalletcorp/pg-pooling';
70
+ import { appLogger } from '@/server/common/logger';
69
71
 
70
72
  let pool: PgPool | undefined;
71
73
 
@@ -81,7 +83,8 @@ export function connectionPooling(): PgPool {
81
83
  application_name: `myapp-${process.env.APP_ENV}`,
82
84
  ssl: process.env.APP_ENV === 'production' ? { rejectUnauthorized: false } : false
83
85
  }, {
84
- debug: process.env.NODE_ENV !== 'production'
86
+ logger: appLogger, // any object with debug/info/warn/error
87
+ sqlLogLevel: 'info'
85
88
  });
86
89
  }
87
90
  return pool;
@@ -140,9 +143,32 @@ All other `pg.PoolConfig` properties (`host`, `port`, `database`, `user`, `passw
140
143
 
141
144
  `PgPoolOptions`:
142
145
 
143
- | Property | Type | Default | Description |
144
- | -------- | ------- | ------- | ------------------------------------------------------------------ |
145
- | `debug` | boolean | false | When `true`, executed SQL and results are logged to `console.debug`. |
146
+ | Property | Type | Default | Description |
147
+ | --------------- | ------------------- | --------- | ------------------------------------------------------------------------------------------------------------- |
148
+ | `logger` | `PgPoolLogger` | - | Destination of all logs. When given, the logger decides which levels are output (`debug` is ignored). |
149
+ | `debug` | boolean | false | Only used without `logger`. When `true`, `debug` / `info` logs are written to `console.debug` / `console.info`. |
150
+ | `sqlLogLevel` | `'debug' \| 'info'` | `'debug'` | Level used for `SQL` / `SQL RESULT` / `BEGIN` / `COMMIT` / `ROLLBACK` logs. |
151
+ | `leakWarnMs` | number | 60000 | Warn `POOL LEAK SUSPECT` when a client is held longer than this. `0` disables it. |
152
+ | `acquireWarnMs` | number | 1000 | Warn `POOL ACQUIRE SLOW` when acquiring takes longer than this or requests are waiting. `0` disables it. |
153
+
154
+ `PgPoolLogger`:
155
+
156
+ ```typescript
157
+ interface PgPoolLogger {
158
+ debug(...args: any[]): void;
159
+ info(...args: any[]): void;
160
+ warn(...args: any[]): void;
161
+ error(...args: any[]): void;
162
+ }
163
+ ```
164
+
165
+ Each log is called with the header `'[PgPooling]'`, a message, and optional details, e.g. `logger.warn('[PgPooling]', 'POOL ACQUIRE SLOW', { elapsedMs, total, idle, waiting })`.
166
+
167
+ | Level | Messages |
168
+ | ------- | ---------------------------------------------------------------------------------- |
169
+ | `debug` / `info` | `SQL`, `SQL RESULT`, `BEGIN`, `COMMIT`, `ROLLBACK` (chosen by `sqlLogLevel`) |
170
+ | `warn` | `POOL ACQUIRE SLOW`, `POOL LEAK SUSPECT`, `POOL RELEASE (after leak suspect)` |
171
+ | `error` | `POOL CONNECT FAILED`, `Idle client error`, `Checked-out client error` |
146
172
 
147
173
  ##### `PgPool` Methods
148
174
 
@@ -167,7 +193,7 @@ All other `pg.PoolConfig` properties (`host`, `port`, `database`, `user`, `passw
167
193
 
168
194
  * Always release clients back to the pool using `release()` to avoid connection leaks.
169
195
  * Use `connect()` and `release()` inside `try/finally` blocks for safe resource management.
170
- * Warnings (slow acquire, connect failure, leak suspect, idle/checked-out client errors) are emitted via `process.emitWarning`. To suppress them, run Node with the `--no-warnings` flag (e.g. `node --no-warnings app.js`, or `NODE_OPTIONS=--no-warnings`).
196
+ * Without `logger`, `warn` / `error` logs are emitted via `process.emitWarning` so that callers can suppress them with the `--no-warnings` flag (e.g. `node --no-warnings app.js`, or `NODE_OPTIONS=--no-warnings`) or handle them with `process.on('warning')`.
171
197
 
172
198
  #### 📜 License
173
199
 
@@ -1,10 +1,39 @@
1
1
  import pg from 'pg';
2
+ /**
3
+ * ログの出力先
4
+ * 渡した場合、どのレベルを出力するかはこのロガーが決める
5
+ */
6
+ export interface PgPoolLogger {
7
+ debug(...args: any[]): void;
8
+ info(...args: any[]): void;
9
+ warn(...args: any[]): void;
10
+ error(...args: any[]): void;
11
+ }
2
12
  export interface PgPoolOptions {
13
+ /** ログの出力先。未指定の場合はconsole(debug/info)とprocess.emitWarning(warn/error)に出力する */
14
+ logger?: PgPoolLogger;
15
+ /** loggerを渡さない場合のみ有効。trueの場合はdebug/infoも出力する */
3
16
  debug?: boolean;
17
+ /** SQL/SQL RESULT/BEGIN/COMMIT/ROLLBACKを出力するレベル */
18
+ sqlLogLevel?: 'debug' | 'info';
19
+ /** 接続の保持がこの時間を超えた場合にリーク疑いとして警告する。0の場合は警告しない */
20
+ leakWarnMs?: number;
21
+ /** 接続の取得がこの時間を超えた場合に警告する。0の場合は警告しない */
22
+ acquireWarnMs?: number;
23
+ }
24
+ /**
25
+ * PgClientの動作設定。PgPoolOptionsの既定値を解決したもの
26
+ */
27
+ export interface PgClientSettings {
28
+ logger: PgPoolLogger;
29
+ sqlLogLevel: 'debug' | 'info';
30
+ leakWarnMs: number;
4
31
  }
5
32
  export declare class PgPool {
6
33
  private pool;
7
- private readonly debug;
34
+ private readonly logger;
35
+ private readonly acquireWarnMs;
36
+ private readonly clientSettings;
8
37
  constructor(config: pg.PoolConfig, options?: PgPoolOptions);
9
38
  getOriginalPool(): pg.Pool;
10
39
  connect(): Promise<PgClient>;
@@ -21,12 +50,12 @@ export declare class PgPool {
21
50
  }
22
51
  export declare class PgClient {
23
52
  private client;
24
- private readonly debug;
53
+ private readonly settings;
25
54
  private acquiredAt;
26
55
  private leakTimer;
27
56
  private leakWarned;
28
57
  private errorListener;
29
- constructor(client: pg.PoolClient, debug?: boolean);
58
+ constructor(client: pg.PoolClient, settings: PgClientSettings);
30
59
  query<R extends pg.QueryResult = pg.QueryResult>(text: string, values?: any[], options?: {
31
60
  suppressLog?: boolean;
32
61
  }): Promise<R>;
@@ -34,5 +63,5 @@ export declare class PgClient {
34
63
  begin(): Promise<pg.QueryResult>;
35
64
  commit(): Promise<pg.QueryResult>;
36
65
  rollback(): Promise<pg.QueryResult>;
37
- private debugLog;
66
+ private sqlLog;
38
67
  }
package/lib/pg-pooling.js CHANGED
@@ -19,15 +19,46 @@ const DEFAULT_IDLE_IN_TRANSACTION_SESSION_TIMEOUT_MS = 60 * 1000; // トラン
19
19
  const DEFAULT_KEEP_ALIVE = true;
20
20
  const DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS = 10 * 1000;
21
21
  // 接続の取得がこの時間を超えた場合に警告する。正常時の取得は新規接続の確立を含めても数百msで収まる
22
- const ACQUIRE_WARN_MS = 1000;
22
+ const DEFAULT_ACQUIRE_WARN_MS = 1000;
23
23
  // 接続の保持がこの時間を超えた場合にリーク疑いとして警告する。
24
24
  // 1クエリの上限(statement_timeout/query_timeout)より長く、サーバ側が放置セッションを切断するidle_in_transaction_session_timeoutと同じ長さ
25
- const LEAK_WARN_MS = 60 * 1000;
25
+ const DEFAULT_LEAK_WARN_MS = 60 * 1000;
26
+ /**
27
+ * loggerが渡されなかった場合のロガー
28
+ * 警告とエラーは呼び出し元が--no-warningsやprocess.on('warning')で抑止・捕捉できるようにprocess.emitWarningで出力する
29
+ *
30
+ * @param {boolean} debug trueの場合はdebug/infoもconsoleに出力する
31
+ * @returns {PgPoolLogger}
32
+ */
33
+ function createDefaultLogger(debug) {
34
+ return {
35
+ debug: (...args) => {
36
+ if (debug) {
37
+ console.debug(...args);
38
+ }
39
+ },
40
+ info: (...args) => {
41
+ if (debug) {
42
+ console.info(...args);
43
+ }
44
+ },
45
+ warn: (...args) => process.emitWarning(util_1.default.format(...args)),
46
+ error: (...args) => process.emitWarning(util_1.default.format(...args))
47
+ };
48
+ }
26
49
  class PgPool {
27
50
  pool;
28
- debug;
51
+ logger;
52
+ acquireWarnMs;
53
+ clientSettings;
29
54
  constructor(config, options) {
30
- this.debug = options?.debug ?? false;
55
+ this.logger = options?.logger ?? createDefaultLogger(options?.debug ?? false);
56
+ this.acquireWarnMs = options?.acquireWarnMs ?? DEFAULT_ACQUIRE_WARN_MS;
57
+ this.clientSettings = {
58
+ logger: this.logger,
59
+ sqlLogLevel: options?.sqlLogLevel ?? 'debug',
60
+ leakWarnMs: options?.leakWarnMs ?? DEFAULT_LEAK_WARN_MS
61
+ };
31
62
  // 各種タイムアウトの既定値を適用する。configで指定された項目はそのまま優先する
32
63
  const mergedConfig = {
33
64
  connectionTimeoutMillis: DEFAULT_CONNECTION_TIMEOUT_MS,
@@ -42,7 +73,7 @@ class PgPool {
42
73
  this.pool.on('error', (error) => {
43
74
  // アイドル接続のエラーはプールに通知する
44
75
  // リスナーが無いとプロセスが落ちるため必ず登録する
45
- process.emitWarning(`${logHeader} Idle client error. ${error.message}`);
76
+ this.logger.error(logHeader, 'Idle client error', error);
46
77
  });
47
78
  }
48
79
  getOriginalPool() {
@@ -55,14 +86,17 @@ class PgPool {
55
86
  const elapsedMs = Date.now() - start;
56
87
  const stats = this.poolStats();
57
88
  // 取得に時間がかかった、あるいは取得待ちの要求が滞留している場合はプール枯渇の前兆として警告する
58
- if (ACQUIRE_WARN_MS <= elapsedMs || 0 < stats.waiting) {
59
- process.emitWarning(`${logHeader} POOL ACQUIRE SLOW. ${JSON.stringify({ elapsedMs, ...stats })}`);
89
+ if (0 < this.acquireWarnMs && (this.acquireWarnMs <= elapsedMs || 0 < stats.waiting)) {
90
+ this.logger.warn(logHeader, 'POOL ACQUIRE SLOW', { elapsedMs, ...stats });
60
91
  }
61
- return new PgClient(client, this.debug);
92
+ return new PgClient(client, this.clientSettings);
62
93
  }
63
94
  catch (error) {
64
95
  // connectionTimeoutMillisによる取得失敗を無言にしない
65
- process.emitWarning(`${logHeader} POOL CONNECT FAILED. ${JSON.stringify({ elapsedMs: Date.now() - start, ...this.poolStats() })} ${error instanceof Error ? error.message : String(error)}`);
96
+ this.logger.error(logHeader, 'POOL CONNECT FAILED', {
97
+ elapsedMs: Date.now() - start,
98
+ ...this.poolStats()
99
+ }, error);
66
100
  throw error;
67
101
  }
68
102
  }
@@ -94,35 +128,40 @@ class PgPool {
94
128
  exports.PgPool = PgPool;
95
129
  class PgClient {
96
130
  client;
97
- debug;
131
+ settings;
98
132
  acquiredAt = Date.now();
99
133
  leakTimer;
100
134
  leakWarned = false;
101
135
  // 貸出中のクライアントに個別のエラーリスナーを設定
102
136
  // これが無いとDB側の瞬断でリスナー不在のerrorイベントが発生し、プロセスが落ちる
103
137
  errorListener = (error) => {
104
- process.emitWarning(`${logHeader} Checked-out client error. ${error.message}`);
138
+ this.settings.logger.error(logHeader, 'Checked-out client error', error);
105
139
  };
106
- constructor(client, debug = false) {
140
+ constructor(client, settings) {
107
141
  this.client = client;
108
- this.debug = debug;
142
+ this.settings = settings;
109
143
  this.client.on('error', this.errorListener);
110
- // リークした接続の取得元を特定できるように、取得時点のスタックトレースを保持する
111
- const acquireStack = new Error('acquired here').stack;
112
- this.leakTimer = setTimeout(() => {
113
- this.leakWarned = true;
114
- process.emitWarning(`${logHeader} POOL LEAK SUSPECT. ${JSON.stringify({ heldMs: Date.now() - this.acquiredAt })}\n${acquireStack}`);
115
- }, LEAK_WARN_MS);
116
- // タイマーが残っていてもプロセスの終了を妨げないようにする
117
- this.leakTimer.unref();
144
+ if (0 < settings.leakWarnMs) {
145
+ // リークした接続の取得元を特定できるように、取得時点のスタックトレースを保持する
146
+ const acquireStack = new Error('acquired here').stack;
147
+ this.leakTimer = setTimeout(() => {
148
+ this.leakWarned = true;
149
+ settings.logger.warn(logHeader, 'POOL LEAK SUSPECT', {
150
+ heldMs: Date.now() - this.acquiredAt,
151
+ acquireStack
152
+ });
153
+ }, settings.leakWarnMs);
154
+ // タイマーが残っていてもプロセスの終了を妨げないようにする
155
+ this.leakTimer.unref();
156
+ }
118
157
  }
119
158
  async query(text, values, options) {
120
159
  if (!options?.suppressLog) {
121
- this.debugLog(logHeader, 'SQL', text, values);
160
+ this.sqlLog(logHeader, 'SQL', text, values);
122
161
  }
123
162
  const result = await this.client.query(text, values);
124
163
  if (!options?.suppressLog) {
125
- this.debugLog(logHeader, 'SQL RESULT', {
164
+ this.sqlLog(logHeader, 'SQL RESULT', {
126
165
  command: result.command,
127
166
  rowCount: result.rowCount,
128
167
  rows: Array.isArray(result.rows)
@@ -136,28 +175,26 @@ class PgClient {
136
175
  clearTimeout(this.leakTimer);
137
176
  if (this.leakWarned) {
138
177
  // リーク疑い警告後に返却されたことを記録する。警告後にこのログが無ければ本物のリークと判断できる
139
- process.emitWarning(`${logHeader} POOL RELEASE (after leak suspect). ${JSON.stringify({ heldMs: Date.now() - this.acquiredAt })}`);
178
+ this.settings.logger.warn(logHeader, 'POOL RELEASE (after leak suspect)', { heldMs: Date.now() - this.acquiredAt });
140
179
  }
141
180
  // 返却後はプール側のリスナー(pool.on('error'))が受け持つ
142
181
  this.client.removeListener('error', this.errorListener);
143
182
  this.client.release();
144
183
  }
145
184
  async begin() {
146
- this.debugLog(logHeader, 'BEGIN');
185
+ this.sqlLog(logHeader, 'BEGIN');
147
186
  return this.client.query('BEGIN');
148
187
  }
149
188
  async commit() {
150
- this.debugLog(logHeader, 'COMMIT');
189
+ this.sqlLog(logHeader, 'COMMIT');
151
190
  return this.client.query('COMMIT');
152
191
  }
153
192
  async rollback() {
154
- this.debugLog(logHeader, 'ROLLBACK');
193
+ this.sqlLog(logHeader, 'ROLLBACK');
155
194
  return this.client.query('ROLLBACK');
156
195
  }
157
- debugLog(...args) {
158
- if (this.debug) {
159
- console.debug(...args);
160
- }
196
+ sqlLog(...args) {
197
+ this.settings.logger[this.settings.sqlLogLevel](...args);
161
198
  }
162
199
  }
163
200
  exports.PgClient = PgClient;
@@ -1 +1 @@
1
- {"version":3,"file":"pg-pooling.js","sourceRoot":"","sources":["../src/pg-pooling.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pg-pooling.js","sourceRoot":"","sources":["../src/pg-pooling.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@digitalwalletcorp/pg-pooling",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "This is a library for PostgreSQL connection pooling",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -46,6 +46,6 @@
46
46
  "ts-jest": "^29.4.9",
47
47
  "ts-node": "^10.9.2",
48
48
  "tsconfig-paths": "^4.2.0",
49
- "typescript": "^6.0.3"
49
+ "typescript": "6.0.3"
50
50
  }
51
51
  }
package/src/pg-pooling.ts CHANGED
@@ -6,8 +6,37 @@ import util from 'util';
6
6
  // SQLの段階でカラムを指定してセレクトできる場合は`SELECT xx_date::TEXT`のように記述すればSQLレベルでYYYY-MM-DD文字列に変換される
7
7
  pg.types.setTypeParser(1082, (v) => v);
8
8
 
9
+ /**
10
+ * ログの出力先
11
+ * 渡した場合、どのレベルを出力するかはこのロガーが決める
12
+ */
13
+ export interface PgPoolLogger {
14
+ debug(...args: any[]): void;
15
+ info(...args: any[]): void;
16
+ warn(...args: any[]): void;
17
+ error(...args: any[]): void;
18
+ }
19
+
9
20
  export interface PgPoolOptions {
21
+ /** ログの出力先。未指定の場合はconsole(debug/info)とprocess.emitWarning(warn/error)に出力する */
22
+ logger?: PgPoolLogger;
23
+ /** loggerを渡さない場合のみ有効。trueの場合はdebug/infoも出力する */
10
24
  debug?: boolean;
25
+ /** SQL/SQL RESULT/BEGIN/COMMIT/ROLLBACKを出力するレベル */
26
+ sqlLogLevel?: 'debug' | 'info';
27
+ /** 接続の保持がこの時間を超えた場合にリーク疑いとして警告する。0の場合は警告しない */
28
+ leakWarnMs?: number;
29
+ /** 接続の取得がこの時間を超えた場合に警告する。0の場合は警告しない */
30
+ acquireWarnMs?: number;
31
+ }
32
+
33
+ /**
34
+ * PgClientの動作設定。PgPoolOptionsの既定値を解決したもの
35
+ */
36
+ export interface PgClientSettings {
37
+ logger: PgPoolLogger;
38
+ sqlLogLevel: 'debug' | 'info';
39
+ leakWarnMs: number;
11
40
  }
12
41
 
13
42
  const logHeader = '[PgPooling]';
@@ -21,17 +50,49 @@ const DEFAULT_KEEP_ALIVE = true;
21
50
  const DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS = 10 * 1000;
22
51
 
23
52
  // 接続の取得がこの時間を超えた場合に警告する。正常時の取得は新規接続の確立を含めても数百msで収まる
24
- const ACQUIRE_WARN_MS = 1000;
53
+ const DEFAULT_ACQUIRE_WARN_MS = 1000;
25
54
  // 接続の保持がこの時間を超えた場合にリーク疑いとして警告する。
26
55
  // 1クエリの上限(statement_timeout/query_timeout)より長く、サーバ側が放置セッションを切断するidle_in_transaction_session_timeoutと同じ長さ
27
- const LEAK_WARN_MS = 60 * 1000;
56
+ const DEFAULT_LEAK_WARN_MS = 60 * 1000;
57
+
58
+ /**
59
+ * loggerが渡されなかった場合のロガー
60
+ * 警告とエラーは呼び出し元が--no-warningsやprocess.on('warning')で抑止・捕捉できるようにprocess.emitWarningで出力する
61
+ *
62
+ * @param {boolean} debug trueの場合はdebug/infoもconsoleに出力する
63
+ * @returns {PgPoolLogger}
64
+ */
65
+ function createDefaultLogger(debug: boolean): PgPoolLogger {
66
+ return {
67
+ debug: (...args: any[]) => {
68
+ if (debug) {
69
+ console.debug(...args);
70
+ }
71
+ },
72
+ info: (...args: any[]) => {
73
+ if (debug) {
74
+ console.info(...args);
75
+ }
76
+ },
77
+ warn: (...args: any[]) => process.emitWarning(util.format(...args)),
78
+ error: (...args: any[]) => process.emitWarning(util.format(...args))
79
+ };
80
+ }
28
81
 
29
82
  export class PgPool {
30
83
  private pool: pg.Pool;
31
- private readonly debug: boolean;
84
+ private readonly logger: PgPoolLogger;
85
+ private readonly acquireWarnMs: number;
86
+ private readonly clientSettings: PgClientSettings;
32
87
 
33
88
  constructor(config: pg.PoolConfig, options?: PgPoolOptions) {
34
- this.debug = options?.debug ?? false;
89
+ this.logger = options?.logger ?? createDefaultLogger(options?.debug ?? false);
90
+ this.acquireWarnMs = options?.acquireWarnMs ?? DEFAULT_ACQUIRE_WARN_MS;
91
+ this.clientSettings = {
92
+ logger: this.logger,
93
+ sqlLogLevel: options?.sqlLogLevel ?? 'debug',
94
+ leakWarnMs: options?.leakWarnMs ?? DEFAULT_LEAK_WARN_MS
95
+ };
35
96
  // 各種タイムアウトの既定値を適用する。configで指定された項目はそのまま優先する
36
97
  const mergedConfig: pg.PoolConfig = {
37
98
  connectionTimeoutMillis: DEFAULT_CONNECTION_TIMEOUT_MS,
@@ -46,7 +107,7 @@ export class PgPool {
46
107
  this.pool.on('error', (error: Error) => {
47
108
  // アイドル接続のエラーはプールに通知する
48
109
  // リスナーが無いとプロセスが落ちるため必ず登録する
49
- process.emitWarning(`${logHeader} Idle client error. ${error.message}`);
110
+ this.logger.error(logHeader, 'Idle client error', error);
50
111
  });
51
112
  }
52
113
 
@@ -61,13 +122,16 @@ export class PgPool {
61
122
  const elapsedMs = Date.now() - start;
62
123
  const stats = this.poolStats();
63
124
  // 取得に時間がかかった、あるいは取得待ちの要求が滞留している場合はプール枯渇の前兆として警告する
64
- if (ACQUIRE_WARN_MS <= elapsedMs || 0 < stats.waiting) {
65
- process.emitWarning(`${logHeader} POOL ACQUIRE SLOW. ${JSON.stringify({ elapsedMs, ...stats })}`);
125
+ if (0 < this.acquireWarnMs && (this.acquireWarnMs <= elapsedMs || 0 < stats.waiting)) {
126
+ this.logger.warn(logHeader, 'POOL ACQUIRE SLOW', { elapsedMs, ...stats });
66
127
  }
67
- return new PgClient(client, this.debug);
128
+ return new PgClient(client, this.clientSettings);
68
129
  } catch (error) {
69
130
  // connectionTimeoutMillisによる取得失敗を無言にしない
70
- process.emitWarning(`${logHeader} POOL CONNECT FAILED. ${JSON.stringify({ elapsedMs: Date.now() - start, ...this.poolStats() })} ${error instanceof Error ? error.message : String(error)}`);
131
+ this.logger.error(logHeader, 'POOL CONNECT FAILED', {
132
+ elapsedMs: Date.now() - start,
133
+ ...this.poolStats()
134
+ }, error);
71
135
  throw error;
72
136
  }
73
137
  }
@@ -104,39 +168,44 @@ export class PgPool {
104
168
 
105
169
  export class PgClient {
106
170
  private client: pg.PoolClient;
107
- private readonly debug: boolean;
171
+ private readonly settings: PgClientSettings;
108
172
  private acquiredAt = Date.now();
109
- private leakTimer: ReturnType<typeof setTimeout>;
173
+ private leakTimer: ReturnType<typeof setTimeout> | undefined;
110
174
  private leakWarned = false;
111
175
  // 貸出中のクライアントに個別のエラーリスナーを設定
112
176
  // これが無いとDB側の瞬断でリスナー不在のerrorイベントが発生し、プロセスが落ちる
113
177
  private errorListener = (error: Error) => {
114
- process.emitWarning(`${logHeader} Checked-out client error. ${error.message}`);
178
+ this.settings.logger.error(logHeader, 'Checked-out client error', error);
115
179
  };
116
180
 
117
- constructor(client: pg.PoolClient, debug = false) {
181
+ constructor(client: pg.PoolClient, settings: PgClientSettings) {
118
182
  this.client = client;
119
- this.debug = debug;
183
+ this.settings = settings;
120
184
  this.client.on('error', this.errorListener);
121
- // リークした接続の取得元を特定できるように、取得時点のスタックトレースを保持する
122
- const acquireStack = new Error('acquired here').stack;
123
- this.leakTimer = setTimeout(() => {
124
- this.leakWarned = true;
125
- process.emitWarning(`${logHeader} POOL LEAK SUSPECT. ${JSON.stringify({ heldMs: Date.now() - this.acquiredAt })}\n${acquireStack}`);
126
- }, LEAK_WARN_MS);
127
- // タイマーが残っていてもプロセスの終了を妨げないようにする
128
- this.leakTimer.unref();
185
+ if (0 < settings.leakWarnMs) {
186
+ // リークした接続の取得元を特定できるように、取得時点のスタックトレースを保持する
187
+ const acquireStack = new Error('acquired here').stack;
188
+ this.leakTimer = setTimeout(() => {
189
+ this.leakWarned = true;
190
+ settings.logger.warn(logHeader, 'POOL LEAK SUSPECT', {
191
+ heldMs: Date.now() - this.acquiredAt,
192
+ acquireStack
193
+ });
194
+ }, settings.leakWarnMs);
195
+ // タイマーが残っていてもプロセスの終了を妨げないようにする
196
+ this.leakTimer.unref();
197
+ }
129
198
  }
130
199
 
131
200
  public async query<R extends pg.QueryResult = pg.QueryResult>(text: string, values?: any[], options?: {
132
201
  suppressLog?: boolean
133
202
  }): Promise<R> {
134
203
  if (!options?.suppressLog) {
135
- this.debugLog(logHeader, 'SQL', text, values);
204
+ this.sqlLog(logHeader, 'SQL', text, values);
136
205
  }
137
206
  const result = await this.client.query(text, values);
138
207
  if (!options?.suppressLog) {
139
- this.debugLog(logHeader, 'SQL RESULT', {
208
+ this.sqlLog(logHeader, 'SQL RESULT', {
140
209
  command: result.command,
141
210
  rowCount: result.rowCount,
142
211
  rows: Array.isArray(result.rows)
@@ -151,7 +220,7 @@ export class PgClient {
151
220
  clearTimeout(this.leakTimer);
152
221
  if (this.leakWarned) {
153
222
  // リーク疑い警告後に返却されたことを記録する。警告後にこのログが無ければ本物のリークと判断できる
154
- process.emitWarning(`${logHeader} POOL RELEASE (after leak suspect). ${JSON.stringify({ heldMs: Date.now() - this.acquiredAt })}`);
223
+ this.settings.logger.warn(logHeader, 'POOL RELEASE (after leak suspect)', { heldMs: Date.now() - this.acquiredAt });
155
224
  }
156
225
  // 返却後はプール側のリスナー(pool.on('error'))が受け持つ
157
226
  this.client.removeListener('error', this.errorListener);
@@ -159,23 +228,21 @@ export class PgClient {
159
228
  }
160
229
 
161
230
  public async begin(): Promise<pg.QueryResult> {
162
- this.debugLog(logHeader, 'BEGIN');
231
+ this.sqlLog(logHeader, 'BEGIN');
163
232
  return this.client.query('BEGIN');
164
233
  }
165
234
 
166
235
  public async commit(): Promise<pg.QueryResult> {
167
- this.debugLog(logHeader, 'COMMIT');
236
+ this.sqlLog(logHeader, 'COMMIT');
168
237
  return this.client.query('COMMIT');
169
238
  }
170
239
 
171
240
  public async rollback(): Promise<pg.QueryResult> {
172
- this.debugLog(logHeader, 'ROLLBACK');
241
+ this.sqlLog(logHeader, 'ROLLBACK');
173
242
  return this.client.query('ROLLBACK');
174
243
  }
175
244
 
176
- private debugLog(...args: any[]): void {
177
- if (this.debug) {
178
- console.debug(...args);
179
- }
245
+ private sqlLog(...args: any[]): void {
246
+ this.settings.logger[this.settings.sqlLogLevel](...args);
180
247
  }
181
248
  }