From 616b802de6add1fbc818523a611f75cde147b930 Mon Sep 17 00:00:00 2001 From: Ken Gullaksen Date: Thu, 28 Sep 2023 13:08:07 +0200 Subject: [PATCH] =?UTF-8?q?eject=20plugins=20fra=20HPM=20for=20=C3=A5=20re?= =?UTF-8?q?dusere=20st=C3=B8y?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ikke log error for nettverksissues - fjerner query delen av requesten i loggene - legger til en ny metrikk for proxy_status e.g. ``` proxy_events_total{target: "foo.com", proxystatus="null",status="504",errcode="ENOTFOUND"} 2 ``` --- server/server.js | 69 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/server/server.js b/server/server.js index eea0662e1..5a155dfcd 100644 --- a/server/server.js +++ b/server/server.js @@ -1,7 +1,12 @@ import path from 'path'; import express from 'express'; import Mustache from 'mustache'; -import httpProxyMiddleware, { responseInterceptor } from 'http-proxy-middleware'; +import httpProxyMiddleware, { + debugProxyErrorsPlugin, + errorResponsePlugin, + proxyEventsPlugin, + responseInterceptor, +} from 'http-proxy-middleware'; import { createHttpTerminator } from 'http-terminator'; import Prometheus from 'prom-client'; import { createLogger, format, transports } from 'winston'; @@ -28,6 +33,11 @@ const log_events_counter = new Prometheus.Counter({ help: 'Antall log events fordelt på level', labelNames: ['level'], }); +const proxy_events_counter = new Prometheus.Counter({ + name: 'proxy_events_total', + help: 'Antall proxy events', + labelNames: ['target', 'proxystatus', 'status', 'errcode'], +}); const maskFormat = format((info) => ({ ...info, @@ -55,6 +65,61 @@ const log = new Proxy( } ); +// copy with mods from http-proxy-middleware https://github.com/chimurai/http-proxy-middleware/blob/master/src/plugins/default/logger-plugin.ts +const loggerPlugin = (proxyServer, options) => { + proxyServer.on('error', (err, req, res, target) => { + const hostname = req?.headers?.host; + // target is undefined when websocket errors + const errReference = 'https://nodejs.org/api/errors.html#errors_common_system_errors'; // link to Node Common Systems Errors page + proxy_events_counter.inc({ + target: target.host, + proxystatus: null, + status: res.statusCode, + errcode: err.code || 'unknown', + }); + const level = + /HPE_INVALID/.test(err.code) || + ['ECONNRESET', 'ENOTFOUND', 'ECONNREFUSED', 'ETIMEDOUT'].includes(err.code) + ? 'warn' + : 'error'; + log.log( + level, + '[HPM] Error occurred while proxying request %s to %s [%s] (%s)', + `${hostname}${req?.host}${req?.path}`, + `${target?.href}`, + err.code || err, + errReference + ); + }); + + proxyServer.on('proxyRes', (proxyRes, req, res) => { + const originalUrl = req.originalUrl ?? `${req.baseUrl || ''}${req.url}`; + const pathUpToSearch = proxyRes.req.path.replace(/\?.*$/, ''); + const exchange = `[HPM] ${req.method} ${originalUrl} -> ${proxyRes.req.protocol}//${proxyRes.req.host}${pathUpToSearch} [${proxyRes.statusCode}]`; + proxy_events_counter.inc({ + target: proxyRes.req.host, + proxystatus: proxyRes.statusCode, + status: res.statusCode, + errcode: null, + }); + log.info(exchange); + }); + + /** + * When client opens WebSocket connection + */ + proxyServer.on('open', (socket) => { + log.info('[HPM] Client connected: %o', socket.address()); + }); + + /** + * When client closes WebSocket connection + */ + proxyServer.on('close', (req, proxySocket, proxyHead) => { + log.info('[HPM] Client disconnected: %o', proxySocket.address()); + }); +}; + log.info(`Frackend startup: ${JSON.stringify({ NAIS_CLUSTER_NAME, MILJO, GIT_COMMIT })}`); let BUILD_PATH = path.join(process.cwd(), '../build'); @@ -132,6 +197,8 @@ const main = async () => { secure: true, xfwd: true, changeOrigin: true, + ejectPlugins: true, + plugins: [debugProxyErrorsPlugin, errorResponsePlugin, loggerPlugin, proxyEventsPlugin], }; app.use( '/min-side-arbeidsgiver/tiltaksgjennomforing-api',