@hvedinich/utils 0.0.62 → 0.0.64

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hvedinich/utils",
3
- "version": "0.0.62",
3
+ "version": "0.0.64",
4
4
  "description": "utils module",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,7 +21,8 @@
21
21
  "axios": "^0.27.2",
22
22
  "express": "4.17.1",
23
23
  "graphql-playground-middleware-express": "1.7.20",
24
- "jsonwebtoken": "8.5.1"
24
+ "jsonwebtoken": "8.5.1",
25
+ "pino": "^9.5.0"
25
26
  },
26
27
  "devDependencies": {
27
28
  "eslint": "^7.2.0",
package/src/log/index.js CHANGED
@@ -1,25 +1,60 @@
1
- const ctxToString = (ctx) => {
2
- if (!ctx) return 'unknown';
3
- let str = '';
4
- if (ctx.uid) {
5
- str += `uid: ${ctx.uid}; `;
6
- }
7
- return str;
1
+ const pino = require('pino');
2
+
3
+ const ctxParser = ctx => {
4
+ if (!ctx) return { uid: 'unknown' };
5
+ return ctx.uid ? { uid: ctx.uid, permission: ctx.permission } : { uid: 'unknown' };
6
+ };
7
+
8
+ const errorParser = error => {
9
+ if (!error) return null;
10
+ return {
11
+ stack: error.stack,
12
+ code: error.code,
13
+ message: error.message,
14
+ status: error.status,
15
+ sanitized: error.sanitized,
16
+ };
17
+ };
18
+
19
+ const PinoLevelToSeverityLookup = {
20
+ debug: 'DEBUG',
21
+ info: 'INFO',
22
+ error: 'ERROR',
8
23
  };
9
24
  module.exports = class Logger {
10
- constructor(name) {
11
- this.name = name;
25
+ constructor(name, environment) {
26
+ this.logger = pino({
27
+ name,
28
+ mixin() {
29
+ return { environment };
30
+ },
31
+ level: 'debug',
32
+ timestamp: pino.stdTimeFunctions.isoTime,
33
+ formatters: {
34
+ level(label, number) {
35
+ return {
36
+ severity: PinoLevelToSeverityLookup[label] || PinoLevelToSeverityLookup.info,
37
+ level: number,
38
+ };
39
+ },
40
+ log: object => {
41
+ const ctx = ctxParser(object?.ctx);
42
+ return { ...object, ctx };
43
+ },
44
+ },
45
+ });
12
46
  }
13
47
 
14
- error(str, ctx) {
15
- console.error(`[${this.name}] [ERROR] ${new Date().toISOString().replace(/[T]|(\..*Z$)+/gi, ' ')}: ${str}`, ctxToString(ctx));
48
+ error(str, ctx, params) {
49
+ const { error, ...fields } = params || {};
50
+ this.logger.error({ ctx, error: errorParser(error), fields }, str);
16
51
  }
17
52
 
18
- info(str, ctx) {
19
- console.log(`[${this.name}] [INFO] ${new Date().toISOString().replace(/[T]|(\..*Z$)+/gi, ' ')}: ${str}`, ctxToString(ctx));
53
+ info(str, ctx, fields) {
54
+ this.logger.info({ ctx, fields }, str);
20
55
  }
21
56
 
22
- debug(str, ctx) {
23
- console.debug(`[${this.name}] [DEBUG] ${new Date().toISOString().replace(/[T]|(\..*Z$)+/gi, ' ')}: ${str}`, ctxToString(ctx));
57
+ debug(str, ctx, fields) {
58
+ this.logger.debug({ ctx, fields }, str);
24
59
  }
25
60
  };
@@ -2,7 +2,10 @@ const express = require('express');
2
2
  const expressPlayground = require('graphql-playground-middleware-express').default;
3
3
  const axios = require('axios');
4
4
  const { ApolloServer, ApolloError } = require('apollo-server-express');
5
- const { guestCtx, token: { EXPIRED, UNAUTHORIZED } } = require('../constants');
5
+ const {
6
+ guestCtx,
7
+ token: { EXPIRED, UNAUTHORIZED },
8
+ } = require('../constants');
6
9
  const { addContext } = require('../utils/contextUtils');
7
10
 
8
11
  const logError = (err, logger = console) => {
@@ -11,15 +14,23 @@ const logError = (err, logger = console) => {
11
14
  description.path = err.path && err.path[0] ? err.path[0] : 'unknown';
12
15
  description.message = err.message;
13
16
  description.serviceName = err.extensions.serviceName;
14
- description.stack = err.extensions && err.extensions.exception
15
- && err.extensions.exception.stacktrace
16
- ? JSON.stringify(err.extensions.exception.stacktrace)
17
- : 'unknown';
17
+ description.stack =
18
+ err.extensions && err.extensions.exception && err.extensions.exception.stacktrace
19
+ ? JSON.stringify(err.extensions.exception.stacktrace)
20
+ : 'unknown';
18
21
  } finally {
19
- logger.error(`path: ${description.path}
20
- message: ${description.message}
21
- serviceName: ${description.serviceName}
22
- stack: ${description.stack}`);
22
+ logger.error(
23
+ `Server error`,
24
+ {},
25
+ {
26
+ error: {
27
+ path: description.path,
28
+ message: description.message,
29
+ serviceName: description.serviceName,
30
+ stack: description.stack,
31
+ },
32
+ },
33
+ );
23
34
  }
24
35
  };
25
36
 
@@ -44,9 +55,7 @@ class Server {
44
55
  this.app.get('/_status', healthCheck || defaultCHealthCheck);
45
56
  }
46
57
 
47
- initGQL({
48
- gateway, schema, context, options, logger, errorHandler,
49
- }) {
58
+ initGQL({ gateway, schema, context, options, logger, errorHandler }) {
50
59
  if (!gateway && !schema) {
51
60
  console.error('Schema not found');
52
61
  return;
@@ -54,7 +63,7 @@ class Server {
54
63
 
55
64
  const serverOptions = {
56
65
  context: context || defaultContext,
57
- formatError: (err) => {
66
+ formatError: err => {
58
67
  logError(err, logger);
59
68
  if (errorHandler) return errorHandler(err);
60
69
  if (err.name === 'TokenExpiredError') {
@@ -67,8 +76,11 @@ class Server {
67
76
  return new ApolloError(err.extensions.sanitized, err.extensions.code, err.extensions);
68
77
  }
69
78
  if (err.extensions && err.extensions.exception && err.extensions.exception.sanitized) {
70
- return new ApolloError(err.extensions.exception.sanitized,
71
- err.extensions.exception.code, err.extensions.exception);
79
+ return new ApolloError(
80
+ err.extensions.exception.sanitized,
81
+ err.extensions.exception.code,
82
+ err.extensions.exception,
83
+ );
72
84
  }
73
85
  if (err.name === 'GraphQLError' || err.name === 'ValidationError') {
74
86
  return new ApolloError(err.message, err.name);
@@ -94,9 +106,7 @@ class Server {
94
106
  }
95
107
 
96
108
  addEndpoints(endpoints) {
97
- endpoints.forEach(({
98
- path, method, handler, proxy,
99
- }) => {
109
+ endpoints.forEach(({ path, method, handler, proxy }) => {
100
110
  if (proxy) {
101
111
  this.app.use(path, proxy);
102
112
  } else {
@@ -115,8 +125,8 @@ const waitServices = async (services = {}, logger = console) => {
115
125
  while (shouldWait) {
116
126
  try {
117
127
  // eslint-disable-next-line no-await-in-loop
118
- const statuses = await Promise.all(Object.values(services)
119
- .map(async ({ wait, name, url }) => {
128
+ const statuses = await Promise.all(
129
+ Object.values(services).map(async ({ wait, name, url }) => {
120
130
  if (!wait) {
121
131
  logger.info(`${name}: ready "true"`);
122
132
  return true;
@@ -128,15 +138,22 @@ const waitServices = async (services = {}, logger = console) => {
128
138
  }
129
139
  logger.info(`${name}: ready "false"`);
130
140
  return false;
131
- }));
141
+ }),
142
+ );
132
143
  if (statuses.every(Boolean)) {
133
144
  shouldWait = false;
134
145
  }
135
- // eslint-disable-next-line no-await-in-loop
146
+ // eslint-disable-next-line no-await-in-loop, no-promise-executor-return
136
147
  await new Promise(res => setTimeout(res, 5000));
137
- } catch (err) {
138
- logger.debug(err);
139
- // eslint-disable-next-line no-await-in-loop
148
+ } catch (error) {
149
+ logger.error(
150
+ `waitServices error`,
151
+ {},
152
+ {
153
+ error,
154
+ },
155
+ );
156
+ // eslint-disable-next-line no-await-in-loop, no-promise-executor-return
140
157
  await new Promise(res => setTimeout(res, 5000));
141
158
  }
142
159
  }
@@ -149,10 +166,14 @@ let isHealthyQueue = true;
149
166
  */
150
167
  const checkIsAlive = () => isHealthyQueue;
151
168
 
152
- const setQueueHealthCheck = (value) => {
169
+ const setQueueHealthCheck = value => {
153
170
  isHealthyQueue = value;
154
171
  };
155
172
 
156
173
  module.exports = {
157
- Server, waitServices, express, checkIsAlive, setQueueHealthCheck,
174
+ Server,
175
+ waitServices,
176
+ express,
177
+ checkIsAlive,
178
+ setQueueHealthCheck,
158
179
  };