如何监控Express与Socket.io服务器的HTTP/WSS请求网络字节出入量
Got it, let's break this down for you. Since you're running Express with Socket.io wrapped around an http.Server, we can split the solution into two clear parts: tracking HTTP request/response bytes, and monitoring WebSocket (WSS) traffic for Socket.io connections. Plus, we'll cover key considerations for your Nginx production setup.
1. Tracking HTTP Request/Response Bytes
We can add an Express middleware to capture incoming and outgoing bytes for every HTTP request. This middleware hooks into the request's data stream and overrides the response's write method to count bytes, then logs/stores the stats once the response finishes.
// Place this middleware BEFORE any body-parsing middleware (like express.json()) app.use((req, res, next) => { // Track incoming request bytes let incomingBytes = 0; req.on('data', (chunk) => { incomingBytes += chunk.length; }); // Track outgoing response bytes let outgoingBytes = 0; const originalWrite = res.write; res.write = function(chunk, encoding, callback) { if (chunk) { // Calculate byte length correctly for buffers or strings outgoingBytes += Buffer.isBuffer(chunk) ? chunk.length : Buffer.byteLength(chunk, encoding); } // Call the original write method to maintain functionality return originalWrite.call(this, chunk, encoding, callback); }; // Log stats when the response is fully sent res.on('finish', () => { console.log(`[HTTP] ${req.method} ${req.path} | In: ${incomingBytes} bytes | Out: ${outgoingBytes} bytes`); // Replace console.log with your monitoring logic (e.g., send to Prometheus, Datadog, or a database) }); next(); });
Critical Note: If you use body-parsing middleware like
express.json()orexpress.urlencoded(), ensure this byte-tracking middleware runs before them. Body parsers consume the request'sdataevent, so our middleware won't capture incoming bytes if it's placed after.
2. Monitoring Socket.io (WSS) Connection Bytes
Socket.io uses Engine.IO under the hood, which provides built-in byte tracking for each connection. The socket.client object (an Engine.IO Client instance) exposes bytesReceived and bytesSent properties that track total bytes for the lifetime of the WebSocket connection.
io.on('connection', (socket) => { const engineClient = socket.client; const socketId = socket.id; console.log(`[Socket] Connected: ${socketId}`); // Option 1: Log total bytes when the socket disconnects socket.on('disconnect', () => { const totalIncoming = engineClient.bytesReceived; const totalOutgoing = engineClient.bytesSent; console.log(`[Socket] Disconnected: ${socketId} | Total In: ${totalIncoming} bytes | Total Out: ${totalOutgoing} bytes`); // Store these stats in your monitoring system as needed }); // Option 2: Periodically log real-time stats (e.g., every 15 seconds) const statsInterval = setInterval(() => { console.log(`[Socket] ${socketId} | Current In: ${engineClient.bytesReceived} bytes | Current Out: ${engineClient.bytesSent} bytes`); }, 15000); // Clean up the interval when the socket disconnects socket.on('disconnect', () => clearInterval(statsInterval)); });
This tracks all WebSocket traffic, including Socket.io's internal protocol frames and your custom messages.
3. Nginx Production Environment Notes
Since you're using Nginx as a reverse proxy, keep these points in mind:
Client-to-Nginx Byte Tracking
If you want to track bytes directly between the client and Nginx (not just Nginx to your Node.js server), configure Nginx to log these values in its access logs. Add a custom log format that includes:
$request_length: Total bytes sent by the client (request headers + body)$bytes_sent: Total bytes sent by Nginx to the client (response headers + body)
Example Nginx config snippet:
log_format app_traffic '$remote_addr - $remote_user [$time_local] "$request" ' '$status $bytes_sent "$http_referer" ' '"$http_user_agent" "$request_length"'; access_log /var/log/nginx/your-app-traffic.log app_traffic;
You can then use tools like Loki+Grafana or the ELK Stack to analyze these logs and aggregate traffic stats.
Nginx-to-Node.js Byte Tracking
The Node.js code above will track bytes between Nginx and your server, but note that these values may differ from client-to-Nginx stats. Nginx may compress responses, add headers, or handle WebSocket frame translation, so the byte counts won't match exactly.
Full Integrated Code
Here's your original code with all the tracking logic added:
const express = require('express') const app = express() const http = require('http').Server(app) const io = require('socket.io')(http) // HTTP Byte Tracking Middleware (place before body parsers) app.use((req, res, next) => { let incomingBytes = 0; req.on('data', (chunk) => { incomingBytes += chunk.length; }); let outgoingBytes = 0; const originalWrite = res.write; res.write = function(chunk, encoding, callback) { if (chunk) { outgoingBytes += Buffer.isBuffer(chunk) ? chunk.length : Buffer.byteLength(chunk, encoding); } return originalWrite.call(this, chunk, encoding, callback); }; res.on('finish', () => { console.log(`[HTTP] ${req.method} ${req.path} | In: ${incomingBytes} bytes | Out: ${outgoingBytes} bytes`); }); next(); }); // Add your body-parsing middleware here (if needed) // app.use(express.json()); // app.use(express.urlencoded({ extended: true })); app.get('/', (req, res) => { res.render('index') }) // Socket.io Byte Tracking io.on('connection', (socket) => { const engineClient = socket.client; const socketId = socket.id; console.log(`[Socket] Connected: ${socketId}`); socket.on('disconnect', () => { const totalIn = engineClient.bytesReceived; const totalOut = engineClient.bytesSent; console.log(`[Socket] Disconnected: ${socketId} | Total In: ${totalIn} bytes | Total Out: ${totalOut} bytes`); }); const statsInterval = setInterval(() => { console.log(`[Socket] ${socketId} | Current In: ${engineClient.bytesReceived} bytes | Current Out: ${engineClient.bytesSent} bytes`); }, 15000); socket.on('disconnect', () => clearInterval(statsInterval)); }) http.listen(8080, () => console.log(`Server is running at 0.0.0.0:8080`))
内容的提问来源于stack exchange,提问作者Amala Amala

