Skip to content

Commit a08628b

Browse files
authored
865 update logs and metrics (#938)
* 865-update-logs-and-metrics. Added the requestId to the server context. Signed-off-by: ebadiere <[email protected]> * Added missing formatters.ts file. Signed-off-by: ebadiere <[email protected]> * Updated year in copyright. Signed-off-by: ebadiere <[email protected]> * Added error logging to the koaJsonRpc. Signed-off-by: ebadiere <[email protected]> * Moved request error messages into constants. Signed-off-by: ebadiere <[email protected]> --------- Signed-off-by: ebadiere <[email protected]>
1 parent 68b23ac commit a08628b

File tree

2 files changed

+39
-7
lines changed

2 files changed

+39
-7
lines changed

packages/server/src/koaJsonRpc/index.ts

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import parse from 'co-body';
2626
import dotenv from 'dotenv';
2727
import path from 'path';
2828
import { Logger } from 'pino';
29+
import { formatRequestIdMessage } from '../formatters';
2930

3031
import {
3132
ParseError,
@@ -42,6 +43,13 @@ import { JsonRpcError } from '@hashgraph/json-rpc-relay';
4243
const hasOwnProperty = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
4344
dotenv.config({ path: path.resolve(__dirname, '../../../../../.env') });
4445

46+
const INTERNAL_ERROR = "INTERNAL ERROR";
47+
const INVALID_PARAMS_ERROR = "INVALID PARAMS ERROR";
48+
const INVALID_REQUEST = "INVALID REQUEST";
49+
const IP_RATE_LIMIT_EXCEEDED = "IP RATE LIMIT EXCEEDED";
50+
const JSON_RPC_ERROR = "JSON RPC ERROR"
51+
const METHOD_NOT_FOUND = "METHOD NOT FOUND";
52+
4553
export default class KoaJsonRpc {
4654
private registry: any;
4755
private registryTotal: any;
@@ -52,6 +60,8 @@ export default class KoaJsonRpc {
5260
private rateLimit: RateLimit;
5361
private koaApp: Koa<Koa.DefaultState, Koa.DefaultContext>;
5462
private requestId: string;
63+
private logger: Logger;
64+
private startTimestamp!: number;
5565

5666
constructor(logger: Logger, register: Registry, opts?) {
5767
this.koaApp = new Koa();
@@ -64,6 +74,7 @@ export default class KoaJsonRpc {
6474
if (opts) {
6575
this.limit = opts.limit || this.limit;
6676
}
77+
this.logger = logger;
6778
this.rateLimit = new RateLimit(logger.child({ name: 'ip-rate-limit' }), register, this.duration);
6879
}
6980

@@ -78,8 +89,12 @@ export default class KoaJsonRpc {
7889

7990
rpcApp() {
8091
return async (ctx, next) => {
81-
let body, result;
92+
this.startTimestamp = ctx.state.start;
93+
let body, ms, result;
8294

95+
this.requestId = ctx.state.reqId;
96+
const requestIdPrefix = formatRequestIdMessage(this.requestId);
97+
8398
if (this.token) {
8499
const headerToken = ctx.get('authorization').split(' ').pop();
85100
if (headerToken !== this.token) {
@@ -96,6 +111,9 @@ export default class KoaJsonRpc {
96111
return;
97112
}
98113

114+
const methodName = body.method;
115+
const messagePrefix = `${requestIdPrefix} [POST] ${methodName}:`;
116+
99117
if (
100118
body.jsonrpc !== '2.0' ||
101119
!hasOwnProperty(body, 'method') ||
@@ -104,21 +122,26 @@ export default class KoaJsonRpc {
104122
) {
105123
ctx.body = jsonResp(body.id || null, new InvalidRequest(), undefined);
106124
ctx.status = 400;
125+
ms = Date.now() - this.startTimestamp;
126+
this.logger.error(`${messagePrefix} ${ctx.status} (${INVALID_REQUEST}) ${ms} ms`);
107127
return;
108128
}
109129

110130
if (!this.registry[body.method]) {
111131
ctx.body = jsonResp(body.id, new MethodNotFound(), undefined);
112132
ctx.status = 400;
133+
ms = Date.now() - this.startTimestamp;
134+
this.logger.error(`${messagePrefix} ${ctx.status} (${METHOD_NOT_FOUND}) ${ms} ms`);
113135
return;
114136
}
115137

116-
this.requestId = ctx.state.reqId;
117-
const methodName = body.method;
138+
118139
const methodTotalLimit = this.registryTotal[methodName];
119140
if (this.rateLimit.shouldRateLimit(ctx.ip, methodName, methodTotalLimit, this.requestId)) {
120141
ctx.body = jsonResp(body.id, new IPRateLimitExceeded(methodName), undefined);
121142
ctx.status = 409;
143+
ms = Date.now() - this.startTimestamp;
144+
this.logger.warn(`${messagePrefix} ${ctx.status} (${IP_RATE_LIMIT_EXCEEDED}) ${ms} ms`);
122145
return;
123146
}
124147

@@ -128,16 +151,22 @@ export default class KoaJsonRpc {
128151
if (e instanceof InvalidParamsError) {
129152
ctx.body = jsonResp(body.id, new InvalidParamsError(e.message), undefined);
130153
ctx.status = 400;
154+
ms = Date.now() - this.startTimestamp;
155+
this.logger.error(`${messagePrefix} ${ctx.status} (${INVALID_PARAMS_ERROR}) ${ms} ms`);
131156
return;
132157
}
133158
ctx.body = jsonResp(body.id, new InternalError(e.message), undefined);
134159
ctx.status = 500;
160+
ms = Date.now() - this.startTimestamp;
161+
this.logger.error(`${messagePrefix} ${ctx.status} (${INTERNAL_ERROR}) ${ms} ms`);
135162
return;
136163
}
137164

138165
ctx.body = jsonResp(body.id, null, result);
139166
if (result instanceof JsonRpcError) {
140167
ctx.status = (result.code == -32603) ? 500 : 400;
168+
ms = Date.now() - this.startTimestamp;
169+
this.logger.error(`${messagePrefix} ${ctx.status} (${result.code}) (${JSON_RPC_ERROR}) ${ms} ms`);
141170
}
142171
};
143172
}
@@ -149,4 +178,8 @@ export default class KoaJsonRpc {
149178
getRequestId(): string {
150179
return this.requestId;
151180
}
181+
182+
getStartTimestamp(): number {
183+
return this.startTimestamp;
184+
}
152185
}

packages/server/src/server.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ const app = new KoaJsonRpc(logger, register, {
4848
limit: process.env.INPUT_SIZE_LIMIT ? process.env.INPUT_SIZE_LIMIT + 'mb' : null
4949
});
5050

51-
const REQUEST_ID_STRING = `Request ID: `;
5251
const responseSuccessStatusCode = '200';
5352
const responseInternalErrorCode = '-32603';
5453
collectDefaultMetrics({ register, prefix: 'rpc_relay_' });
@@ -166,13 +165,13 @@ app.getKoaApp().use(async (ctx, next) => {
166165
ctx.set(options.expose, id);
167166
}
168167

168+
ctx.state.start = Date.now();
169169
ctx.state.reqId = id;
170170

171171
return next();
172172
});
173173

174174
const logAndHandleResponse = async (methodName: any, methodParams: any, methodFunction: any) => {
175-
const start = Date.now();
176175
let ms;
177176

178177
const requestId = app.getRequestId();
@@ -189,7 +188,7 @@ const logAndHandleResponse = async (methodName: any, methodParams: any, methodFu
189188

190189
const response = await methodFunction(requestId);
191190
const status = response instanceof JsonRpcError ? response.code.toString() : responseSuccessStatusCode;
192-
ms = Date.now() - start;
191+
ms = Date.now() - app.getStartTimestamp();
193192
methodResponseHistogram.labels(methodName, status).observe(ms);
194193
logger.info(`${messagePrefix} ${status} ${ms} ms `);
195194
if (response instanceof JsonRpcError) {
@@ -203,7 +202,7 @@ const logAndHandleResponse = async (methodName: any, methodParams: any, methodFu
203202
}
204203
return response;
205204
} catch (e: any) {
206-
ms = Date.now() - start;
205+
ms = Date.now() - app.getStartTimestamp();
207206
methodResponseHistogram.labels(methodName, responseInternalErrorCode).observe(ms);
208207
logger.error(e, `${messagePrefix} ${responseInternalErrorCode} ${ms} ms`);
209208

0 commit comments

Comments
 (0)