pms_md 1.0.0 → 1.0.2

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.
@@ -0,0 +1,321 @@
1
+ # MySQL2 & Sequelize Monitoring Guide
2
+
3
+ This guide shows you how to use the Node Monitor package with MySQL2 and Sequelize.
4
+
5
+ ## 📦 Installation
6
+
7
+ ```bash
8
+ # Install the monitoring package
9
+ npm install pms_md
10
+
11
+ # Install MySQL2 (required)
12
+ npm install mysql2
13
+
14
+ # Install Sequelize (optional, if using ORM)
15
+ npm install sequelize
16
+ ```
17
+
18
+ ---
19
+
20
+ ## 🔧 MySQL2 Setup
21
+
22
+ ### Option 1: MySQL2 Promise Pool (Recommended)
23
+
24
+ ```javascript
25
+ const mysql = require('mysql2/promise');
26
+ const NodeMonitor = require('pms_md');
27
+
28
+ // Create MySQL2 connection pool
29
+ const pool = mysql.createPool({
30
+ host: 'localhost',
31
+ user: 'root',
32
+ password: 'your-password',
33
+ database: 'your-database',
34
+ waitForConnections: true,
35
+ connectionLimit: 10,
36
+ queueLimit: 0
37
+ });
38
+
39
+ // Initialize monitor
40
+ const monitor = new NodeMonitor({
41
+ app: {
42
+ name: 'My App',
43
+ version: '1.0.0'
44
+ }
45
+ });
46
+
47
+ // Register MySQL2 pool for monitoring
48
+ monitor.registerDatabase('mysql', 'mysql2', pool);
49
+
50
+ // Start monitoring
51
+ monitor.start();
52
+ ```
53
+
54
+ ### Option 2: MySQL2 Callback-based Connection
55
+
56
+ ```javascript
57
+ const mysql = require('mysql2');
58
+
59
+ const connection = mysql.createConnection({
60
+ host: 'localhost',
61
+ user: 'root',
62
+ password: 'your-password',
63
+ database: 'your-database'
64
+ });
65
+
66
+ connection.connect();
67
+
68
+ // Register for monitoring
69
+ monitor.registerDatabase('mysql', 'mysql2', connection);
70
+ ```
71
+
72
+ ---
73
+
74
+ ## 🎯 Sequelize Setup
75
+
76
+ ### Basic Sequelize Configuration
77
+
78
+ ```javascript
79
+ const { Sequelize } = require('sequelize');
80
+ const NodeMonitor = require('pms_md');
81
+
82
+ // Create Sequelize instance
83
+ const sequelize = new Sequelize('database', 'username', 'password', {
84
+ host: 'localhost',
85
+ dialect: 'mysql', // or 'postgres', 'sqlite', 'mssql'
86
+ logging: false,
87
+ pool: {
88
+ max: 5,
89
+ min: 0,
90
+ acquire: 30000,
91
+ idle: 10000
92
+ }
93
+ });
94
+
95
+ // Initialize monitor
96
+ const monitor = new NodeMonitor({
97
+ app: {
98
+ name: 'Sequelize App',
99
+ version: '1.0.0'
100
+ },
101
+ notifications: {
102
+ email: {
103
+ enabled: true,
104
+ host: 'smtp.gmail.com',
105
+ port: 587,
106
+ auth: {
107
+ user: 'your-email@gmail.com',
108
+ pass: 'your-app-password'
109
+ },
110
+ recipients: ['admin@example.com']
111
+ }
112
+ }
113
+ });
114
+
115
+ // Test connection and register
116
+ async function setupDatabase() {
117
+ try {
118
+ await sequelize.authenticate();
119
+ console.log('Database connected successfully');
120
+
121
+ // Register Sequelize instance for monitoring
122
+ monitor.registerDatabase('mydb', 'sequelize', sequelize);
123
+
124
+ // Start monitoring
125
+ monitor.start();
126
+ } catch (error) {
127
+ console.error('Unable to connect to database:', error);
128
+ }
129
+ }
130
+
131
+ setupDatabase();
132
+ ```
133
+
134
+ ---
135
+
136
+ ## 🚀 Complete Express + Sequelize Example
137
+
138
+ ```javascript
139
+ const express = require('express');
140
+ const { Sequelize } = require('sequelize');
141
+ const NodeMonitor = require('pms_md');
142
+
143
+ // Initialize Sequelize
144
+ const sequelize = new Sequelize('myapp', 'root', 'password', {
145
+ host: 'localhost',
146
+ dialect: 'mysql'
147
+ });
148
+
149
+ // Initialize Monitor
150
+ const monitor = new NodeMonitor({
151
+ app: { name: 'My App', version: '1.0.0' }
152
+ });
153
+
154
+ const app = express();
155
+ app.use(express.json());
156
+
157
+ // Add monitoring middleware
158
+ app.use(monitor.requestLogger());
159
+
160
+ // Health check
161
+ app.get('/health', monitor.healthCheckEndpoint());
162
+
163
+ // Your routes
164
+ app.get('/users', monitor.asyncHandler(async (req, res) => {
165
+ const [users] = await sequelize.query('SELECT * FROM users');
166
+ res.json(users);
167
+ }));
168
+
169
+ // Error handling
170
+ app.use(monitor.notFoundHandler());
171
+ app.use(monitor.errorMiddleware());
172
+
173
+ // Start server
174
+ async function start() {
175
+ await sequelize.authenticate();
176
+ monitor.registerDatabase('mysql', 'sequelize', sequelize);
177
+
178
+ const server = app.listen(3000, () => {
179
+ console.log('Server running on port 3000');
180
+ monitor.start();
181
+ monitor.setupGracefulShutdown(server);
182
+ });
183
+ }
184
+
185
+ start();
186
+ ```
187
+
188
+ ---
189
+
190
+ ## 📊 Monitoring Features
191
+
192
+ ### Get Database Statistics
193
+
194
+ ```javascript
195
+ // Get MySQL connection stats
196
+ const stats = await monitor.getDatabaseStats('mysql');
197
+ console.log(stats);
198
+ // Output: { type: 'mysql', threadsConnected: 5 }
199
+
200
+ // Get Sequelize stats
201
+ const seqStats = await monitor.getDatabaseStats('mydb');
202
+ console.log(seqStats);
203
+ // Output: {
204
+ // type: 'sequelize',
205
+ // dialect: 'mysql',
206
+ // database: 'myapp',
207
+ // host: 'localhost',
208
+ // pool: { size: 5, available: 3, using: 2, waiting: 0 }
209
+ // }
210
+ ```
211
+
212
+ ### Custom Health Checks
213
+
214
+ ```javascript
215
+ // Add custom database health check
216
+ monitor.registerHealthCheck('database', async () => {
217
+ try {
218
+ await sequelize.authenticate();
219
+ return true;
220
+ } catch {
221
+ return false;
222
+ }
223
+ });
224
+
225
+ // Check health status
226
+ app.get('/health', monitor.healthCheckEndpoint());
227
+ ```
228
+
229
+ ### Monitor Connection Status
230
+
231
+ ```javascript
232
+ // Get all database connection statuses
233
+ const status = monitor.getStatus();
234
+ console.log(status.databases);
235
+ // Output: {
236
+ // mysql: { type: 'sequelize', connected: true, consecutiveFailures: 0 }
237
+ // }
238
+ ```
239
+
240
+ ---
241
+
242
+ ## 🔔 Automatic Notifications
243
+
244
+ The monitor will automatically send notifications when:
245
+
246
+ - ✅ Database connection is lost
247
+ - ✅ Database connection is restored
248
+ - ✅ Connection check fails multiple times
249
+ - ✅ Query timeout occurs
250
+
251
+ Configure email notifications:
252
+
253
+ ```javascript
254
+ const monitor = new NodeMonitor({
255
+ notifications: {
256
+ email: {
257
+ enabled: true,
258
+ host: 'smtp.gmail.com',
259
+ port: 587,
260
+ auth: {
261
+ user: 'your-email@gmail.com',
262
+ pass: 'your-app-password'
263
+ },
264
+ recipients: ['admin@example.com']
265
+ }
266
+ }
267
+ });
268
+ ```
269
+
270
+ ---
271
+
272
+ ## 🛠️ Troubleshooting
273
+
274
+ ### Connection Issues
275
+
276
+ ```javascript
277
+ // Test Sequelize connection
278
+ try {
279
+ await sequelize.authenticate();
280
+ console.log('✅ Connection successful');
281
+ } catch (error) {
282
+ console.error('❌ Connection failed:', error);
283
+ }
284
+ ```
285
+
286
+ ### Check Monitor Logs
287
+
288
+ ```bash
289
+ # View application logs
290
+ cat logs/application-*.log
291
+
292
+ # View error logs
293
+ cat logs/error-*.log
294
+ ```
295
+
296
+ ---
297
+
298
+ ## 📚 Additional Resources
299
+
300
+ - [Sequelize Documentation](https://sequelize.org/)
301
+ - [MySQL2 Documentation](https://github.com/sidorares/node-mysql2)
302
+ - [Node Monitor README](../README.md)
303
+ - [Getting Started Guide](../GETTING_STARTED.md)
304
+
305
+ ---
306
+
307
+ ## 💡 Best Practices
308
+
309
+ 1. **Use Connection Pooling**: Always use connection pools in production
310
+ 2. **Set Timeouts**: Configure appropriate query timeouts
311
+ 3. **Monitor Regularly**: Check database health at regular intervals
312
+ 4. **Handle Errors**: Always wrap database queries in try-catch blocks
313
+ 5. **Graceful Shutdown**: Close database connections on app shutdown
314
+
315
+ ```javascript
316
+ monitor.setupGracefulShutdown(server, async () => {
317
+ await sequelize.close();
318
+ console.log('Database connection closed');
319
+ });
320
+ ```
321
+
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Example: Using Node Monitor with Sequelize and MySQL2
3
+ *
4
+ * This example demonstrates how to integrate the monitoring package
5
+ * with Sequelize ORM and MySQL2 database.
6
+ */
7
+
8
+ const express = require('express');
9
+ const { Sequelize } = require('sequelize');
10
+ const NodeMonitor = require('../src/index');
11
+
12
+ // Initialize Sequelize with MySQL2
13
+ const sequelize = new Sequelize('asset_tracking', 'root', 'password', {
14
+ host: 'localhost',
15
+ dialect: 'mysql',
16
+ logging: false, // Disable SQL logging
17
+ pool: {
18
+ max: 5,
19
+ min: 0,
20
+ acquire: 30000,
21
+ idle: 10000
22
+ }
23
+ });
24
+
25
+ // Initialize Node Monitor
26
+ const monitor = new NodeMonitor({
27
+ app: {
28
+ name: 'Sequelize MySQL App',
29
+ version: '1.0.0',
30
+ environment: process.env.NODE_ENV || 'development'
31
+ },
32
+ notifications: {
33
+ email: {
34
+ enabled: true,
35
+ host: 'smtp.gmail.com',
36
+ port: 587,
37
+ auth: {
38
+ user: process.env.EMAIL_USER || 'your-email@gmail.com',
39
+ pass: process.env.EMAIL_PASS || 'your-app-password'
40
+ },
41
+ from: process.env.EMAIL_USER || 'your-email@gmail.com',
42
+ recipients: [process.env.EMAIL_RECIPIENTS || 'admin@example.com']
43
+ }
44
+ },
45
+ database: {
46
+ enabled: true,
47
+ queryTimeout: 5000
48
+ }
49
+ });
50
+
51
+ // Create Express app
52
+ const app = express();
53
+ app.use(express.json());
54
+
55
+ // Add monitoring middleware
56
+ app.use(monitor.requestLogger());
57
+
58
+ // Health check endpoint
59
+ app.get('/health', monitor.healthCheckEndpoint());
60
+
61
+ // Dashboard endpoint
62
+ app.get('/dashboard', monitor.dashboardEndpoint());
63
+
64
+ // Example routes
65
+ app.get('/', (req, res) => {
66
+ res.json({
67
+ message: 'Sequelize MySQL Monitoring Example',
68
+ status: 'running'
69
+ });
70
+ });
71
+
72
+ // Example database query endpoint
73
+ app.get('/db-test', monitor.asyncHandler(async (req, res) => {
74
+ // Test database connection
75
+ await sequelize.authenticate();
76
+
77
+ // Execute a simple query
78
+ const [results] = await sequelize.query('SELECT 1 + 1 AS result');
79
+
80
+ res.json({
81
+ message: 'Database connection successful',
82
+ result: results
83
+ });
84
+ }));
85
+
86
+ // Get database stats
87
+ app.get('/db-stats', monitor.asyncHandler(async (req, res) => {
88
+ const stats = await monitor.getDatabaseStats('mysql');
89
+ res.json(stats);
90
+ }));
91
+
92
+ // Error handling middleware (must be last)
93
+ app.use(monitor.notFoundHandler());
94
+ app.use(monitor.errorMiddleware());
95
+
96
+ // Start server
97
+ async function startServer() {
98
+ try {
99
+ // Test database connection
100
+ console.log('Testing database connection...');
101
+ await sequelize.authenticate();
102
+ console.log('✅ Database connection established successfully.');
103
+
104
+ // Register database for monitoring
105
+ monitor.registerDatabase('mysql', 'sequelize', sequelize);
106
+ console.log('✅ Database registered for monitoring.');
107
+
108
+ // Register custom health check for database
109
+ monitor.registerHealthCheck('database', async () => {
110
+ try {
111
+ await sequelize.authenticate();
112
+ return true;
113
+ } catch {
114
+ return false;
115
+ }
116
+ });
117
+
118
+ // Start the server
119
+ const PORT = process.env.PORT || 3000;
120
+ const server = app.listen(PORT, () => {
121
+ console.log(`\n🚀 Server running on http://localhost:${PORT}`);
122
+ console.log(`📊 Health check: http://localhost:${PORT}/health`);
123
+ console.log(`📈 Dashboard: http://localhost:${PORT}/dashboard`);
124
+ console.log(`🔍 DB Test: http://localhost:${PORT}/db-test`);
125
+ console.log(`📊 DB Stats: http://localhost:${PORT}/db-stats\n`);
126
+
127
+ // Start monitoring
128
+ monitor.start();
129
+ console.log('✅ Monitoring started\n');
130
+
131
+ // Setup graceful shutdown
132
+ monitor.setupGracefulShutdown(server, async () => {
133
+ console.log('Closing database connection...');
134
+ await sequelize.close();
135
+ console.log('Database connection closed.');
136
+ });
137
+ });
138
+
139
+ } catch (error) {
140
+ console.error('❌ Unable to start server:', error);
141
+ process.exit(1);
142
+ }
143
+ }
144
+
145
+ // Start the application
146
+ startServer();
147
+
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@projectmd/node-monitor",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Comprehensive monitoring solution for Node.js applications with error tracking, health checks, and multi-channel notifications",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -47,7 +47,8 @@
47
47
  "express": "^4.18.0 || ^5.0.0",
48
48
  "mongoose": "^7.0.0 || ^8.0.0",
49
49
  "pg": "^8.11.0",
50
- "mysql2": "^3.6.0",
50
+ "mysql2": "^2.0.0 || ^3.0.0",
51
+ "sequelize": "^6.0.0",
51
52
  "ioredis": "^5.3.0"
52
53
  },
53
54
  "peerDependenciesMeta": {
@@ -63,6 +64,9 @@
63
64
  "mysql2": {
64
65
  "optional": true
65
66
  },
67
+ "sequelize": {
68
+ "optional": true
69
+ },
66
70
  "ioredis": {
67
71
  "optional": true
68
72
  }
@@ -104,18 +104,22 @@ class DbConnectionMonitor {
104
104
  case 'mongodb':
105
105
  case 'mongoose':
106
106
  return this.checkMongoConnection(connection);
107
-
107
+
108
108
  case 'postgresql':
109
109
  case 'postgres':
110
110
  case 'pg':
111
111
  return this.checkPostgresConnection(connection, testQuery);
112
-
112
+
113
113
  case 'mysql':
114
+ case 'mysql2':
114
115
  return this.checkMySqlConnection(connection, testQuery);
115
-
116
+
117
+ case 'sequelize':
118
+ return this.checkSequelizeConnection(connection);
119
+
116
120
  case 'redis':
117
121
  return this.checkRedisConnection(connection);
118
-
122
+
119
123
  default:
120
124
  throw new Error(`Unsupported database type: ${type}`);
121
125
  }
@@ -160,16 +164,48 @@ class DbConnectionMonitor {
160
164
  }
161
165
 
162
166
  /**
163
- * Check MySQL connection
167
+ * Check MySQL/MySQL2 connection
164
168
  */
165
169
  async checkMySqlConnection(connection, testQuery = 'SELECT 1') {
166
170
  try {
167
- const [rows] = await Promise.race([
168
- connection.query(testQuery),
171
+ // Support for mysql2 pool or connection
172
+ if (connection.query) {
173
+ const result = await Promise.race([
174
+ connection.query(testQuery),
175
+ this.timeout(this.config.database.queryTimeout)
176
+ ]);
177
+ // mysql2 returns [rows, fields]
178
+ return Array.isArray(result) ? !!result[0] : !!result;
179
+ }
180
+
181
+ // Support for mysql2 promise pool
182
+ if (connection.execute) {
183
+ const [rows] = await Promise.race([
184
+ connection.execute(testQuery),
185
+ this.timeout(this.config.database.queryTimeout)
186
+ ]);
187
+ return !!rows;
188
+ }
189
+
190
+ return false;
191
+ } catch (error) {
192
+ this.logger.logWarning('mysql_check_failed', `MySQL connection check failed: ${error.message}`);
193
+ return false;
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Check Sequelize connection
199
+ */
200
+ async checkSequelizeConnection(connection) {
201
+ try {
202
+ await Promise.race([
203
+ connection.authenticate(),
169
204
  this.timeout(this.config.database.queryTimeout)
170
205
  ]);
171
- return !!rows;
172
- } catch {
206
+ return true;
207
+ } catch (error) {
208
+ this.logger.logWarning('sequelize_check_failed', `Sequelize connection check failed: ${error.message}`);
173
209
  return false;
174
210
  }
175
211
  }
@@ -275,18 +311,22 @@ class DbConnectionMonitor {
275
311
  case 'mongodb':
276
312
  case 'mongoose':
277
313
  return this.getMongoStats(connection);
278
-
314
+
279
315
  case 'postgresql':
280
316
  case 'postgres':
281
317
  case 'pg':
282
318
  return this.getPostgresStats(connection);
283
-
319
+
284
320
  case 'mysql':
321
+ case 'mysql2':
285
322
  return this.getMySqlStats(connection);
286
-
323
+
324
+ case 'sequelize':
325
+ return this.getSequelizeStats(connection);
326
+
287
327
  case 'redis':
288
328
  return this.getRedisStats(connection);
289
-
329
+
290
330
  default:
291
331
  return { type, status: 'unknown' };
292
332
  }
@@ -333,21 +373,63 @@ class DbConnectionMonitor {
333
373
  }
334
374
 
335
375
  /**
336
- * Get MySQL statistics
376
+ * Get MySQL/MySQL2 statistics
337
377
  */
338
378
  async getMySqlStats(connection) {
339
379
  try {
340
- const [rows] = await connection.query('SHOW STATUS LIKE "Threads_connected"');
341
-
380
+ let rows;
381
+
382
+ // Try mysql2 format first
383
+ if (connection.query) {
384
+ const result = await connection.query('SHOW STATUS LIKE "Threads_connected"');
385
+ rows = Array.isArray(result) ? result[0] : result;
386
+ } else if (connection.execute) {
387
+ [rows] = await connection.execute('SHOW STATUS LIKE "Threads_connected"');
388
+ }
389
+
342
390
  return {
343
391
  type: 'mysql',
344
- threadsConnected: rows[0]?.Value || 0
392
+ threadsConnected: rows?.[0]?.Value || 0
345
393
  };
346
394
  } catch (error) {
347
395
  return { type: 'mysql', error: error.message };
348
396
  }
349
397
  }
350
398
 
399
+ /**
400
+ * Get Sequelize statistics
401
+ */
402
+ async getSequelizeStats(connection) {
403
+ try {
404
+ // Get database dialect
405
+ const dialect = connection.getDialect();
406
+
407
+ // Get pool information if available
408
+ const poolInfo = connection.connectionManager?.pool
409
+ ? {
410
+ size: connection.connectionManager.pool.size || 0,
411
+ available: connection.connectionManager.pool.available || 0,
412
+ using: connection.connectionManager.pool.using || 0,
413
+ waiting: connection.connectionManager.pool.waiting || 0
414
+ }
415
+ : null;
416
+
417
+ // Get basic connection info
418
+ const dbName = connection.config?.database || 'unknown';
419
+ const host = connection.config?.host || 'unknown';
420
+
421
+ return {
422
+ type: 'sequelize',
423
+ dialect,
424
+ database: dbName,
425
+ host,
426
+ pool: poolInfo
427
+ };
428
+ } catch (error) {
429
+ return { type: 'sequelize', error: error.message };
430
+ }
431
+ }
432
+
351
433
  /**
352
434
  * Get Redis statistics
353
435
  */