From 121b0a048e0f53cc381dff1617f88ccf91bf1f0e Mon Sep 17 00:00:00 2001
From: Chris Key <chrisk@packt.com>
Date: Fri, 14 Feb 2020 15:44:20 +0000
Subject: [PATCH 1/4] Added context and changed parameter structure to object

---
 package-lock.json                |  2 +-
 package.json                     |  6 ++---
 src/lib/IConfig.ts               |  8 ++++++
 src/lib/error-custom.ts          | 44 +++++++++++++++++++++++---------
 tests/error-custom-built.spec.js | 17 ++++++++++++
 tests/error-custom.spec.ts       | 17 ++++++++++++
 6 files changed, 78 insertions(+), 16 deletions(-)
 create mode 100644 src/lib/IConfig.ts

diff --git a/package-lock.json b/package-lock.json
index 90b7b3e..a4af08b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "@packt/error-custom",
-  "version": "1.2.0",
+  "version": "2.0.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/package.json b/package.json
index 34f090c..bf20fad 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@packt/error-custom",
-  "version": "1.2.0",
+  "version": "2.0.0",
   "description": "Extends the JavaScript Error object with custom properties.",
   "repository": {
     "type": "git",
@@ -45,7 +45,7 @@
     "@types/chai": "^4.1.7",
     "@types/debug": "^4.1.4",
     "@types/joi": "^14.3.3",
-    "@types/mocha": "^5.2.5",
+    "@types/mocha": "^5.2.7",
     "@types/nock": "^9.3.1",
     "@types/sinon": "^7.0.13",
     "@types/uuid": "^3.4.5",
@@ -92,7 +92,7 @@
     ],
     "reporter": [
       "lcov",
-      "html"
+      "text"
     ],
     "all": true
   }
diff --git a/src/lib/IConfig.ts b/src/lib/IConfig.ts
new file mode 100644
index 0000000..dfaa519
--- /dev/null
+++ b/src/lib/IConfig.ts
@@ -0,0 +1,8 @@
+export interface IConfig {
+  message: string;
+  statusCode: number;
+  errorCode: number;
+  baseError?: Error;
+  logFunction?: string | Function;
+  context: any;
+}
diff --git a/src/lib/error-custom.ts b/src/lib/error-custom.ts
index 1769980..b60fb4c 100644
--- a/src/lib/error-custom.ts
+++ b/src/lib/error-custom.ts
@@ -1,3 +1,4 @@
+/* eslint-disable no-param-reassign */
 import debug from 'debug';
 import joi from 'joi';
 import v4 from 'uuid/v4';
@@ -5,6 +6,8 @@ import url from 'url';
 import winston from 'winston';
 import Elasticsearch from 'winston-elasticsearch';
 import { Client } from '@elastic/elasticsearch';
+// eslint-disable-next-line no-unused-vars
+import { IConfig } from './IConfig';
 
 /**
  * Error with enforced error Code and status Code and autogenerated error ID uuid.
@@ -15,6 +18,7 @@ class ErrorCustom extends Error {
   public manuallyThrown: boolean;
   public id: string;
   public innerException: any;
+  public context: any;
 
   /**
    * Error Constructor
@@ -24,26 +28,41 @@ class ErrorCustom extends Error {
    * Logs the final object using passed function or debug library.
    *
    * @constructor
-   * @param {string} message
-   * Error message to set on the Error object
+   * @param {string | IConfig} message
+   * Error message to set on the Error object, or config properties to set all params
    *
    * @param {number} statusCode
-   * HTTP status code
+   * HTTP status code, optional as it can be passed as part of the config
    *
    * @param {number} errorCode
-   * The specific error code as defined in documentation
+   * The specific error code as defined in documentation, optional as it can be passed as
+   * part of the config
    *
-   * @param {Error} baseError
+   * @param {Error?} baseError
    * Optional base exception to be included as innerException property
    *
    * @param {string | Function} logFunction
    * Optional function to log the error with. If not supplied, debug library will be used
    * to log to the console with the tag `error-custom`
    */
-  constructor(message: string, statusCode: number, errorCode: number,
-    baseError?: Error, logFunction?: string | Function) {
+  constructor(message: string | IConfig, statusCode?: number, errorCode?: number,
+    baseError?: Error, logFunction?: string | Function, context?: any) {
+    let messageVal: string;
+
+    // handle the case where we have a config object passed in and remap into params
+    if (typeof message === 'object') {
+      messageVal = message.message;
+      statusCode = message.statusCode;
+      errorCode = message.errorCode;
+      baseError = message.baseError;
+      logFunction = message.logFunction;
+      context = message.context;
+    } else {
+      messageVal = message;
+    }
+
     // Validation
-    const messageValidation = joi.validate(message, joi.string().required());
+    const messageValidation = joi.validate(messageVal, joi.string().required());
     const statusCodeValidation = joi.validate(
       statusCode,
       joi.number().integer().min(200).max(600)
@@ -65,13 +84,14 @@ class ErrorCustom extends Error {
 
     // Re-enable the original chain for stack traces etc
     /* istanbul ignore next */
-    super(message);
+    super(messageVal);
     Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
     this.statusCode = statusCode;
     this.errorCode = errorCode;
     this.manuallyThrown = true;
     this.id = v4();
     this.innerException = baseError;
+    this.context = context;
 
     // Log to chosen location
     if (process.env.ELASTIC_LOGGING_URL) {
@@ -114,7 +134,7 @@ class ErrorCustom extends Error {
    * @param id
    * @param content
    */
-  private static defaultOutput(id: string, content: ErrorCustom): void {
+  private static defaultOutput(id: string, content: any): void {
     return debug('error-custom')(id, content);
   }
 
@@ -125,7 +145,7 @@ class ErrorCustom extends Error {
    * @param content
    */
   private static async sendToElastic(node: string, content: ErrorCustom): Promise<void> {
-    ErrorCustom.defaultOutput(content.id, content);
+    ErrorCustom.defaultOutput(content.id, content.toJSON());
 
     const date = new Date();
 
@@ -173,7 +193,7 @@ class ErrorCustom extends Error {
         esTransport,
       ],
     });
-    logger.error(content.message, content);
+    logger.error(content.message, content.toJSON());
   }
 }
 
diff --git a/tests/error-custom-built.spec.js b/tests/error-custom-built.spec.js
index 833ecc2..70d2c5b 100644
--- a/tests/error-custom-built.spec.js
+++ b/tests/error-custom-built.spec.js
@@ -19,6 +19,23 @@ describe('Error Custom (Built)', () => {
     expect(error.stack).to.be.not.undefined;
   });
 
+  it('Constructing the instance - object version', () => {
+    const error = new errorCustom({
+      message: 'Error Message',
+      statusCode: 400,
+      errorCode: 1000,
+      context: { productId: '9781234567890' },
+    });
+    expect(error).to.be.instanceof(errorCustom);
+    expect(error.message).to.equal('Error Message');
+    expect(error.statusCode).to.equal(400);
+    expect(error.errorCode).to.equal(1000);
+    expect(error.manuallyThrown).to.be.true;
+    expect(error.stack).to.be.not.undefined;
+    expect(error.context).to.be.a('object');
+    expect(error.context.productId).to.eql('9781234567890');
+  });
+
   it('undefined message fails', () => {
     try {
       new errorCustom(undefined, 200, 1000000);
diff --git a/tests/error-custom.spec.ts b/tests/error-custom.spec.ts
index 45dc1ac..b034843 100644
--- a/tests/error-custom.spec.ts
+++ b/tests/error-custom.spec.ts
@@ -27,6 +27,23 @@ describe('Error Custom', () => {
       expect(error.stack).to.be.not.undefined;
     });
 
+    it('Constructing the instance - object version', () => {
+      const error = new ErrorCustom({
+        message: 'Error Message',
+        statusCode: 400,
+        errorCode: 1000,
+        context: { productId: '9781234567890' },
+      });
+      expect(error).to.be.instanceof(ErrorCustom);
+      expect(error.message).to.equal('Error Message');
+      expect(error.statusCode).to.equal(400);
+      expect(error.errorCode).to.equal(1000);
+      expect(error.manuallyThrown).to.be.true;
+      expect(error.stack).to.be.not.undefined;
+      expect(error.context).to.be.a('object');
+      expect(error.context.productId).to.eql('9781234567890');
+    });
+
     it('undefined message fails', () => {
       try {
         new ErrorCustom(undefined, 200, 1000000);

From 52bab5933db683d756a94f66c21e35efb4e11c10 Mon Sep 17 00:00:00 2001
From: Chris Key <chrisk@packt.com>
Date: Fri, 14 Feb 2020 16:05:43 +0000
Subject: [PATCH 2/4] Fixed bad tests not fulfilling contract

---
 package-lock.json          | 31 ++++++++++++++++++++++++-------
 package.json               |  3 ++-
 src/lib/error-custom.ts    |  3 +++
 tests/error-custom.spec.ts | 16 ++++++++--------
 tsconfig.json              |  2 +-
 5 files changed, 38 insertions(+), 17 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index a4af08b..945d246 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1270,6 +1270,17 @@
         "lodash": "^4.17.4",
         "mkdirp": "^0.5.1",
         "source-map-support": "^0.4.15"
+      },
+      "dependencies": {
+        "source-map-support": {
+          "version": "0.4.18",
+          "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+          "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+          "dev": true,
+          "requires": {
+            "source-map": "^0.5.6"
+          }
+        }
       }
     },
     "babel-runtime": {
@@ -1410,8 +1421,7 @@
     "buffer-from": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
-      "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==",
-      "dev": true
+      "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ=="
     },
     "builtin-modules": {
       "version": "1.1.1",
@@ -5527,12 +5537,19 @@
       "dev": true
     },
     "source-map-support": {
-      "version": "0.4.18",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
-      "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
-      "dev": true,
+      "version": "0.5.16",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
+      "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
       "requires": {
-        "source-map": "^0.5.6"
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+        }
       }
     },
     "spawn-wrap": {
diff --git a/package.json b/package.json
index bf20fad..d684895 100644
--- a/package.json
+++ b/package.json
@@ -12,7 +12,7 @@
     "test": "npm run lint && npm run build && npm run unit && npm run nunit",
     "lint": "eslint ./src/**/*.*s",
     "lint:fix": "eslint ./src/**/*.*s ./tests/**/*.*s --fix",
-    "unit": "mocha --require ts-node/register --require source-map-support/register --recursive 'tests/**/*.spec.*s'",
+    "unit": "mocha --require ts-node/register --recursive 'tests/**/*.spec.*s'",
     "nunit": "nyc --check-coverage true mocha --require ts-node/register --recursive 'tests/**/*.spec.*s'",
     "build": "tsc",
     "prepublishOnly": "npm run test && npm run build"
@@ -71,6 +71,7 @@
     "aws-sdk": "^2.570.0",
     "debug": "4.1.1",
     "joi": "14.3.1",
+    "source-map-support": "^0.5.16",
     "uuid": "3.3.2",
     "winston": "3.2.1",
     "winston-elasticsearch": "0.8.2"
diff --git a/src/lib/error-custom.ts b/src/lib/error-custom.ts
index b60fb4c..e5b3203 100644
--- a/src/lib/error-custom.ts
+++ b/src/lib/error-custom.ts
@@ -6,6 +6,8 @@ import url from 'url';
 import winston from 'winston';
 import Elasticsearch from 'winston-elasticsearch';
 import { Client } from '@elastic/elasticsearch';
+// eslint-disable-next-line import/no-extraneous-dependencies
+import 'source-map-support/register';
 // eslint-disable-next-line no-unused-vars
 import { IConfig } from './IConfig';
 
@@ -86,6 +88,7 @@ class ErrorCustom extends Error {
     /* istanbul ignore next */
     super(messageVal);
     Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
+    this.toJSON = this.toJSON.bind(this);
     this.statusCode = statusCode;
     this.errorCode = errorCode;
     this.manuallyThrown = true;
diff --git a/tests/error-custom.spec.ts b/tests/error-custom.spec.ts
index b034843..7914ecf 100644
--- a/tests/error-custom.spec.ts
+++ b/tests/error-custom.spec.ts
@@ -216,7 +216,7 @@ describe('Error Custom', () => {
       const errorFunc = sandbox.stub(winston, 'createLogger').returns({
         error: () => { },
       } as any);
-      await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {});
+      await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {});
       expect(errorFunc.callCount).to.be.gte(1);
     });
 
@@ -227,7 +227,7 @@ describe('Error Custom', () => {
       const errorFunc = sandbox.stub(winston, 'createLogger').returns({
         error: () => { },
       } as any);
-      await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {});
+      await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {});
       expect(errorFunc.callCount).to.be.gte(1);
     });
 
@@ -240,7 +240,7 @@ describe('Error Custom', () => {
         const errorFunc = sandbox.stub(winston, 'createLogger').returns({
           error: () => { },
         } as any);
-        await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {});
+        await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {});
         expect(errorFunc.callCount).to.be.gte(1);
       });
 
@@ -252,7 +252,7 @@ describe('Error Custom', () => {
         const errorFunc = sandbox.stub(winston, 'createLogger').returns({
           error: () => { },
         } as any);
-        await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {});
+        await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {});
         expect(errorFunc.callCount).to.be.gte(1);
       });
 
@@ -264,7 +264,7 @@ describe('Error Custom', () => {
         const errorFunc = sandbox.stub(winston, 'createLogger').returns({
           error: () => { },
         } as any);
-        await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {});
+        await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {});
         expect(errorFunc.callCount).to.be.gte(1);
       });
 
@@ -276,7 +276,7 @@ describe('Error Custom', () => {
         const errorFunc = sandbox.stub(winston, 'createLogger').returns({
           error: () => { },
         } as any);
-        await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {});
+        await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {});
         expect(errorFunc.callCount).to.be.gte(1);
       });
 
@@ -288,7 +288,7 @@ describe('Error Custom', () => {
         const errorFunc = sandbox.stub(winston, 'createLogger').returns({
           error: () => { },
         } as any);
-        await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {});
+        await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {});
         expect(errorFunc.callCount).to.be.gte(1);
       });
 
@@ -300,7 +300,7 @@ describe('Error Custom', () => {
         const errorFunc = sandbox.stub(winston, 'createLogger').returns({
           error: () => { },
         } as any);
-        await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, uuid(), {});
+        await (ErrorCustom as any).sendToElastic(ELASTIC_LOGGING_URL, new ErrorCustom(uuid(), 500, 123455), {});
         expect(errorFunc.callCount).to.be.gte(1);
       });
     });
diff --git a/tsconfig.json b/tsconfig.json
index 48d9a87..c2df81d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -4,7 +4,7 @@
       "es2017"
     ],
     "module": "commonjs",
-    "target": "es5",
+    "target": "es2015",
     "noImplicitAny": false,
     "sourceMap": true,
     "emitDecoratorMetadata": true,

From 531be198f7b8fb3de5c79fcff1d18739ffa68ad4 Mon Sep 17 00:00:00 2001
From: Chris Key <chrisk@packt.com>
Date: Fri, 14 Feb 2020 16:10:00 +0000
Subject: [PATCH 3/4] Updated readme

---
 README.md | 26 ++++++++++++++++++++++----
 1 file changed, 22 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md
index e9afd9b..ccdbe0a 100644
--- a/README.md
+++ b/README.md
@@ -15,18 +15,36 @@ Logs the final object using passed function, Elastic URL or `Debug` library with
 const error = new ErrorCustom(message, statusCode, errorCode, baseError, logFunction);
 ```
 
-   * {string} `message`
-Error message to set on the Error object
+   * {string | IConfig} `message`
+Error message to set on the Error object, or a config object for all parameters
    * {number} `statusCode`
-HTTP status code
+HTTP status code, optional as it can be passed as part of the config
    * {number} `errorCode`
-The specific error code as defined in documentation
+The specific error code as defined in documentation, optional as it can be passed as part of the config
    * {Error} `baseError`
 Optional base exception to be included as innerException property
    * {Function|string} `logFunction`
 Optional function to log the error with. If not supplied, debug library will be used
 to log to the console with the tag `error-custom`. If a string is provided that is a
 URL, it will be used to send to that URL with ElasticSearch client in Winston format.
+   * {object} `context`
+Optional context information to provide with the error
+
+## IConfig definition
+An `Iconfig` object can be apssed instead of individual parameters as below, where the definition are the same as the constructor.
+```
+export interface IConfig {
+    message: string;
+    statusCode: number;
+    errorCode: number;
+    baseError?: Error;
+    logFunction?: string | Function;
+    context: any;
+}
+```
+
+## toJSON
+The object includes a `toJSON()` override to make all parameters iterable. Note that this returns an object, not a JSON string.
 
 ## Environment Variables
 Functionality can be modified with various environment variables:

From bb57788f5b6ec97961325134013fe4dc6b79315d Mon Sep 17 00:00:00 2001
From: supachris28 <keych.ck@gmail.com>
Date: Fri, 27 Mar 2020 15:49:56 +0000
Subject: [PATCH 4/4] Added try/catch and upgraded joi

---
 package-lock.json       | 174 +++++++++++++++++++---------------------
 package.json            |   4 +-
 src/lib/error-custom.ts |  58 +++++++-------
 3 files changed, 116 insertions(+), 120 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 945d246..a71e9bb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -45,9 +45,9 @@
           }
         },
         "minimist": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "version": "1.2.5",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+          "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
           "dev": true
         }
       }
@@ -242,6 +242,49 @@
         }
       }
     },
+    "@hapi/address": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@hapi/address/-/address-4.0.1.tgz",
+      "integrity": "sha512-0oEP5UiyV4f3d6cBL8F3Z5S7iWSX39Knnl0lY8i+6gfmmIBj44JCBNtcMgwyS+5v7j3VYavNay0NFHDS+UGQcw==",
+      "requires": {
+        "@hapi/hoek": "^9.0.0"
+      }
+    },
+    "@hapi/formula": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-2.0.0.tgz",
+      "integrity": "sha512-V87P8fv7PI0LH7LiVi8Lkf3x+KCO7pQozXRssAHNXXL9L1K+uyu4XypLXwxqVDKgyQai6qj3/KteNlrqDx4W5A=="
+    },
+    "@hapi/hoek": {
+      "version": "9.0.4",
+      "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.0.4.tgz",
+      "integrity": "sha512-EwaJS7RjoXUZ2cXXKZZxZqieGtc7RbvQhUy8FwDoMQtxWVi14tFjeFCYPZAM1mBCpOpiBpyaZbb9NeHc7eGKgw=="
+    },
+    "@hapi/joi": {
+      "version": "17.1.1",
+      "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-17.1.1.tgz",
+      "integrity": "sha512-p4DKeZAoeZW4g3u7ZeRo+vCDuSDgSvtsB/NpfjXEHTUjSeINAi/RrVOWiVQ1isaoLzMvFEhe8n5065mQq1AdQg==",
+      "requires": {
+        "@hapi/address": "^4.0.1",
+        "@hapi/formula": "^2.0.0",
+        "@hapi/hoek": "^9.0.0",
+        "@hapi/pinpoint": "^2.0.0",
+        "@hapi/topo": "^5.0.0"
+      }
+    },
+    "@hapi/pinpoint": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-2.0.0.tgz",
+      "integrity": "sha512-vzXR5MY7n4XeIvLpfl3HtE3coZYO4raKXW766R6DZw/6aLqR26iuZ109K7a0NtF2Db0jxqh7xz2AxkUwpUFybw=="
+    },
+    "@hapi/topo": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz",
+      "integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==",
+      "requires": {
+        "@hapi/hoek": "^9.0.0"
+      }
+    },
     "@sinonjs/commons": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.4.0.tgz",
@@ -296,10 +339,10 @@
       "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==",
       "dev": true
     },
-    "@types/joi": {
-      "version": "14.3.3",
-      "resolved": "https://registry.npmjs.org/@types/joi/-/joi-14.3.3.tgz",
-      "integrity": "sha512-6gAT/UkIzYb7zZulAbcof3lFxpiD5EI6xBeTvkL1wYN12pnFQ+y/+xl9BvnVgxkmaIDN89xWhGZLD9CvuOtZ9g==",
+    "@types/hapi__joi": {
+      "version": "16.0.12",
+      "resolved": "https://registry.npmjs.org/@types/hapi__joi/-/hapi__joi-16.0.12.tgz",
+      "integrity": "sha512-xJYifuz59jXdWY5JMS15uvA3ycS3nQYOGqoIIE0+fwQ0qI3/4CxBc6RHsOTp6wk9M0NWEdpcTl02lOQOKMifbQ==",
       "dev": true
     },
     "@types/json-schema": {
@@ -432,9 +475,9 @@
       "dev": true
     },
     "acorn": {
-      "version": "6.2.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz",
-      "integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==",
+      "version": "6.4.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
+      "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
       "dev": true
     },
     "acorn-jsx": {
@@ -2550,8 +2593,7 @@
         "ansi-regex": {
           "version": "2.1.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "aproba": {
           "version": "1.2.0",
@@ -2572,14 +2614,12 @@
         "balanced-match": {
           "version": "1.0.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"
@@ -2594,20 +2634,17 @@
         "code-point-at": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "concat-map": {
           "version": "0.0.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "console-control-strings": {
           "version": "1.1.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "core-util-is": {
           "version": "1.0.2",
@@ -2724,8 +2761,7 @@
         "inherits": {
           "version": "2.0.3",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "ini": {
           "version": "1.3.5",
@@ -2737,7 +2773,6 @@
           "version": "1.0.0",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "number-is-nan": "^1.0.0"
           }
@@ -2752,7 +2787,6 @@
           "version": "3.0.4",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -2760,14 +2794,12 @@
         "minimist": {
           "version": "0.0.8",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "minipass": {
           "version": "2.3.5",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "safe-buffer": "^5.1.2",
             "yallist": "^3.0.0"
@@ -2786,7 +2818,6 @@
           "version": "0.5.1",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "minimist": "0.0.8"
           }
@@ -2867,8 +2898,7 @@
         "number-is-nan": {
           "version": "1.0.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "object-assign": {
           "version": "4.1.1",
@@ -2880,7 +2910,6 @@
           "version": "1.4.0",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "wrappy": "1"
           }
@@ -2966,8 +2995,7 @@
         "safe-buffer": {
           "version": "5.1.2",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "safer-buffer": {
           "version": "2.1.2",
@@ -3003,7 +3031,6 @@
           "version": "1.0.2",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "code-point-at": "^1.0.0",
             "is-fullwidth-code-point": "^1.0.0",
@@ -3023,7 +3050,6 @@
           "version": "3.0.1",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
           }
@@ -3067,14 +3093,12 @@
         "wrappy": {
           "version": "1.0.2",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "yallist": {
           "version": "3.0.3",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         }
       }
     },
@@ -3140,7 +3164,6 @@
       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
       "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
       "dev": true,
-      "optional": true,
       "requires": {
         "is-glob": "^2.0.0"
       }
@@ -3226,11 +3249,6 @@
       "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
       "dev": true
     },
-    "hoek": {
-      "version": "6.1.2",
-      "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.2.tgz",
-      "integrity": "sha512-6qhh/wahGYZHFSFw12tBbJw5fsAhhwrrG/y3Cs0YMTv2WzMnL0oLPnQJjv1QJvEfylRSOFuP+xCu+tdx0tD16Q=="
-    },
     "home-or-tmp": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
@@ -3247,6 +3265,12 @@
       "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==",
       "dev": true
     },
+    "html-escaper": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+      "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+      "dev": true
+    },
     "iconv-lite": {
       "version": "0.4.24",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -3416,8 +3440,7 @@
       "version": "1.1.6",
       "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
       "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
-      "dev": true,
-      "optional": true
+      "dev": true
     },
     "is-builtin-module": {
       "version": "1.0.0",
@@ -3466,8 +3489,7 @@
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
       "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
-      "dev": true,
-      "optional": true
+      "dev": true
     },
     "is-finite": {
       "version": "1.0.2",
@@ -3489,7 +3511,6 @@
       "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
       "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
       "dev": true,
-      "optional": true,
       "requires": {
         "is-extglob": "^1.0.0"
       }
@@ -3550,14 +3571,6 @@
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
       "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
     },
-    "isemail": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz",
-      "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==",
-      "requires": {
-        "punycode": "2.x.x"
-      }
-    },
     "isexe": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -3783,12 +3796,12 @@
       }
     },
     "istanbul-reports": {
-      "version": "2.2.6",
-      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz",
-      "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==",
+      "version": "2.2.7",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.7.tgz",
+      "integrity": "sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg==",
       "dev": true,
       "requires": {
-        "handlebars": "^4.1.2"
+        "html-escaper": "^2.0.0"
       }
     },
     "jmespath": {
@@ -3796,16 +3809,6 @@
       "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz",
       "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc="
     },
-    "joi": {
-      "version": "14.3.1",
-      "resolved": "https://registry.npmjs.org/joi/-/joi-14.3.1.tgz",
-      "integrity": "sha512-LQDdM+pkOrpAn4Lp+neNIFV3axv1Vna3j38bisbQhETPMANYRbFJFUyOZcOClYvM/hppMhGWuKSFEK9vjrB+bQ==",
-      "requires": {
-        "hoek": "6.x.x",
-        "isemail": "3.x.x",
-        "topo": "3.x.x"
-      }
-    },
     "js-tokens": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
@@ -3877,7 +3880,6 @@
       "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
       "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
       "dev": true,
-      "optional": true,
       "requires": {
         "is-buffer": "^1.1.5"
       }
@@ -4568,7 +4570,6 @@
       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
       "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
       "dev": true,
-      "optional": true,
       "requires": {
         "remove-trailing-separator": "^1.0.1"
       }
@@ -5141,7 +5142,8 @@
     "punycode": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+      "dev": true
     },
     "querystring": {
       "version": "0.2.0",
@@ -5168,9 +5170,9 @@
           "optional": true
         },
         "kind-of": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+          "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
           "dev": true,
           "optional": true
         }
@@ -5310,15 +5312,13 @@
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
       "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
-      "dev": true,
-      "optional": true
+      "dev": true
     },
     "repeat-element": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
       "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
-      "dev": true,
-      "optional": true
+      "dev": true
     },
     "repeat-string": {
       "version": "1.6.1",
@@ -5883,14 +5883,6 @@
       "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
       "dev": true
     },
-    "topo": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz",
-      "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==",
-      "requires": {
-        "hoek": "6.x.x"
-      }
-    },
     "trim-right": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
diff --git a/package.json b/package.json
index d684895..0292065 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,7 @@
     "@babel/core": "^7.4.4",
     "@types/chai": "^4.1.7",
     "@types/debug": "^4.1.4",
-    "@types/joi": "^14.3.3",
+    "@types/hapi__joi": "^16.0.12",
     "@types/mocha": "^5.2.7",
     "@types/nock": "^9.3.1",
     "@types/sinon": "^7.0.13",
@@ -68,9 +68,9 @@
   },
   "dependencies": {
     "@elastic/elasticsearch": "^7.4.0",
+    "@hapi/joi": "^17.1.1",
     "aws-sdk": "^2.570.0",
     "debug": "4.1.1",
-    "joi": "14.3.1",
     "source-map-support": "^0.5.16",
     "uuid": "3.3.2",
     "winston": "3.2.1",
diff --git a/src/lib/error-custom.ts b/src/lib/error-custom.ts
index e5b3203..48ebd7f 100644
--- a/src/lib/error-custom.ts
+++ b/src/lib/error-custom.ts
@@ -1,6 +1,6 @@
 /* eslint-disable no-param-reassign */
 import debug from 'debug';
-import joi from 'joi';
+import joi from '@hapi/joi';
 import v4 from 'uuid/v4';
 import url from 'url';
 import winston from 'winston';
@@ -64,16 +64,16 @@ class ErrorCustom extends Error {
     }
 
     // Validation
-    const messageValidation = joi.validate(messageVal, joi.string().required());
-    const statusCodeValidation = joi.validate(
-      statusCode,
-      joi.number().integer().min(200).max(600)
-        .required(),
-    );
-    const errorCodeValidation = joi.validate(
-      errorCode,
-      joi.alternatives([joi.string(), joi.number().integer()]).required(),
-    );
+    const messageValidation = joi.string().required().validate(messageVal);
+    const statusCodeValidation = joi.number().integer().min(200).max(600)
+      .required()
+      .validate(
+        statusCode,
+      );
+    const errorCodeValidation = joi.alternatives([joi.string(), joi.number().integer()]).required()
+      .validate(
+        errorCode,
+      );
     const errors = [];
     if (messageValidation.error) errors.push('Invalid value for message parameter');
     if (statusCodeValidation.error) errors.push('Invalid value for statusCode parameter');
@@ -97,25 +97,29 @@ class ErrorCustom extends Error {
     this.context = context;
 
     // Log to chosen location
-    if (process.env.ELASTIC_LOGGING_URL) {
-      ErrorCustom.sendToElastic(process.env.ELASTIC_LOGGING_URL, this);
-    } else {
-      switch (typeof logFunction) {
-        case 'function':
-          logFunction(this.id, this);
-          break;
-        case 'string':
-          if (url.parse(logFunction).host) {
-            ErrorCustom.sendToElastic(logFunction, this);
+    try {
+      if (process.env.ELASTIC_LOGGING_URL) {
+        ErrorCustom.sendToElastic(process.env.ELASTIC_LOGGING_URL, this);
+      } else {
+        switch (typeof logFunction) {
+          case 'function':
+            logFunction(this.id, this);
             break;
-          } else {
+          case 'string':
+            if (url.parse(logFunction).host) {
+              ErrorCustom.sendToElastic(logFunction, this);
+              break;
+            } else {
+              ErrorCustom.defaultOutput(this.id, this);
+              break;
+            }
+
+          default:
             ErrorCustom.defaultOutput(this.id, this);
-            break;
-          }
-
-        default:
-          ErrorCustom.defaultOutput(this.id, this);
+        }
       }
+    } catch (error) {
+      console.error('Logging attempts failed', error);
     }
   }