浏览代码

Add logging

Craig Fletcher 4 年之前
父节点
当前提交
8de3d7b176
共有 8 个文件被更改,包括 259 次插入18 次删除
  1. 1 0
      .gitignore
  2. 5 3
      README.md
  3. 204 0
      package-lock.json
  4. 3 1
      package.json
  5. 6 5
      src/easy-api.js
  6. 3 3
      src/index.js
  7. 30 0
      src/modules/logging.js
  8. 7 6
      src/routes/hello.js

+ 1 - 0
.gitignore

@@ -1,2 +1,3 @@
 node_modules
 node_modules
+logs
 .env
 .env

+ 5 - 3
README.md

@@ -4,6 +4,7 @@ Quick and dirty API boilerplate, using:
   * Redis for the DB 
   * Redis for the DB 
   * Yup for validation
   * Yup for validation
   * Restify for the web server/routing
   * Restify for the web server/routing
+  * Winston for logging
 
 
 There are many limitations to this configuration, it is intended as a
 There are many limitations to this configuration, it is intended as a
 debugging/prototyping tool.
 debugging/prototyping tool.
@@ -26,13 +27,14 @@ start(
 ## Storage
 ## Storage
 
 
 Objects are stored in redis by calculating the sha256 hash, hex digest from a
 Objects are stored in redis by calculating the sha256 hash, hex digest from a
-"path" array for convenience (e.g. ["users", req.params.userName, "stats", "visits"]).
+"path" array for convenience (e.g. `["users", req.params.userName, "stats",
+"visits"]`).
 
 
 
 
 ## Routes
 ## Routes
 
 
-Routes are defined as simple factories, passed a db wrapper and yup instance as
-an object ({db, yup}) and expected to return:
+Routes are defined as simple factories, passed a db wrapper, yup and log instance as
+an object ({db, yup, log}) and expected to return:
   * type: HTTP verb, e.g. `get`
   * type: HTTP verb, e.g. `get`
   * route: restify path string, e.g. `/api/hello/:name`
   * route: restify path string, e.g. `/api/hello/:name`
   * handler: restify handler function for route
   * handler: restify handler function for route

+ 204 - 0
package-lock.json

@@ -57,6 +57,17 @@
         "regenerator-runtime": "^0.13.4"
         "regenerator-runtime": "^0.13.4"
       }
       }
     },
     },
+    "@dabh/diagnostics": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.2.tgz",
+      "integrity": "sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==",
+      "dev": true,
+      "requires": {
+        "colorspace": "1.1.x",
+        "enabled": "2.0.x",
+        "kuler": "^2.0.0"
+      }
+    },
     "@eslint/eslintrc": {
     "@eslint/eslintrc": {
       "version": "0.4.1",
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz",
       "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.1.tgz",
@@ -173,6 +184,12 @@
         "color-convert": "^1.9.0"
         "color-convert": "^1.9.0"
       }
       }
     },
     },
+    "app-root-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz",
+      "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==",
+      "dev": true
+    },
     "argparse": {
     "argparse": {
       "version": "1.0.10",
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -225,6 +242,12 @@
       "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
       "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
       "dev": true
       "dev": true
     },
     },
+    "async": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
+      "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==",
+      "dev": true
+    },
     "balanced-match": {
     "balanced-match": {
       "version": "1.0.2",
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -324,6 +347,16 @@
         }
         }
       }
       }
     },
     },
+    "color": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz",
+      "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^1.9.1",
+        "color-string": "^1.5.2"
+      }
+    },
     "color-convert": {
     "color-convert": {
       "version": "1.9.3",
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -339,6 +372,32 @@
       "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
       "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
       "dev": true
       "dev": true
     },
     },
+    "color-string": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz",
+      "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==",
+      "dev": true,
+      "requires": {
+        "color-name": "^1.0.0",
+        "simple-swizzle": "^0.2.2"
+      }
+    },
+    "colors": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+      "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+      "dev": true
+    },
+    "colorspace": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz",
+      "integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==",
+      "dev": true,
+      "requires": {
+        "color": "3.0.x",
+        "text-hex": "1.0.x"
+      }
+    },
     "concat-map": {
     "concat-map": {
       "version": "0.0.1",
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -481,6 +540,12 @@
       "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
       "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
       "dev": true
       "dev": true
     },
     },
+    "enabled": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
+      "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==",
+      "dev": true
+    },
     "encodeurl": {
     "encodeurl": {
       "version": "1.0.2",
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@@ -876,6 +941,18 @@
       "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
       "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
       "dev": true
       "dev": true
     },
     },
+    "fast-safe-stringify": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz",
+      "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==",
+      "dev": true
+    },
+    "fecha": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz",
+      "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==",
+      "dev": true
+    },
     "file-entry-cache": {
     "file-entry-cache": {
       "version": "6.0.1",
       "version": "6.0.1",
       "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
       "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -945,6 +1022,12 @@
       "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==",
       "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==",
       "dev": true
       "dev": true
     },
     },
+    "fn.name": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
+      "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==",
+      "dev": true
+    },
     "formidable": {
     "formidable": {
       "version": "1.2.2",
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz",
       "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz",
@@ -1361,6 +1444,12 @@
         "verror": "1.10.0"
         "verror": "1.10.0"
       }
       }
     },
     },
+    "kuler": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
+      "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==",
+      "dev": true
+    },
     "levn": {
     "levn": {
       "version": "0.4.1",
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -1421,6 +1510,27 @@
       "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
       "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
       "dev": true
       "dev": true
     },
     },
+    "logform": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz",
+      "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==",
+      "dev": true,
+      "requires": {
+        "colors": "^1.2.1",
+        "fast-safe-stringify": "^2.0.4",
+        "fecha": "^4.2.0",
+        "ms": "^2.1.1",
+        "triple-beam": "^1.3.0"
+      },
+      "dependencies": {
+        "ms": {
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+          "dev": true
+        }
+      }
+    },
     "lru-cache": {
     "lru-cache": {
       "version": "5.1.1",
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -1604,6 +1714,15 @@
         "wrappy": "1"
         "wrappy": "1"
       }
       }
     },
     },
+    "one-time": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
+      "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
+      "dev": true,
+      "requires": {
+        "fn.name": "1.x.x"
+      }
+    },
     "optionator": {
     "optionator": {
       "version": "0.9.1",
       "version": "0.9.1",
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -2009,6 +2128,23 @@
         "object-inspect": "^1.9.0"
         "object-inspect": "^1.9.0"
       }
       }
     },
     },
+    "simple-swizzle": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+      "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
+      "dev": true,
+      "requires": {
+        "is-arrayish": "^0.3.1"
+      },
+      "dependencies": {
+        "is-arrayish": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+          "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+          "dev": true
+        }
+      }
+    },
     "slice-ansi": {
     "slice-ansi": {
       "version": "4.0.0",
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
       "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
@@ -2155,6 +2291,12 @@
         "tweetnacl": "~0.14.0"
         "tweetnacl": "~0.14.0"
       }
       }
     },
     },
+    "stack-trace": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
+      "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=",
+      "dev": true
+    },
     "statuses": {
     "statuses": {
       "version": "1.4.0",
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
@@ -2278,6 +2420,12 @@
         }
         }
       }
       }
     },
     },
+    "text-hex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
+      "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
+      "dev": true
+    },
     "text-table": {
     "text-table": {
       "version": "0.2.0",
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -2289,6 +2437,12 @@
       "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
       "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
       "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA="
       "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA="
     },
     },
+    "triple-beam": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
+      "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==",
+      "dev": true
+    },
     "tsconfig-paths": {
     "tsconfig-paths": {
       "version": "3.9.0",
       "version": "3.9.0",
       "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
       "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz",
@@ -2415,6 +2569,56 @@
         "is-symbol": "^1.0.3"
         "is-symbol": "^1.0.3"
       }
       }
     },
     },
+    "winston": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz",
+      "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==",
+      "dev": true,
+      "requires": {
+        "@dabh/diagnostics": "^2.0.2",
+        "async": "^3.1.0",
+        "is-stream": "^2.0.0",
+        "logform": "^2.2.0",
+        "one-time": "^1.0.0",
+        "readable-stream": "^3.4.0",
+        "stack-trace": "0.0.x",
+        "triple-beam": "^1.3.0",
+        "winston-transport": "^4.4.0"
+      }
+    },
+    "winston-transport": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz",
+      "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==",
+      "dev": true,
+      "requires": {
+        "readable-stream": "^2.3.7",
+        "triple-beam": "^1.2.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "2.3.7",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+          "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+          "dev": true,
+          "requires": {
+            "core-util-is": "~1.0.0",
+            "inherits": "~2.0.3",
+            "isarray": "~1.0.0",
+            "process-nextick-args": "~2.0.0",
+            "safe-buffer": "~5.1.1",
+            "string_decoder": "~1.1.1",
+            "util-deprecate": "~1.0.1"
+          }
+        },
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+          "dev": true
+        }
+      }
+    },
     "word-wrap": {
     "word-wrap": {
       "version": "1.2.3",
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
       "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",

+ 3 - 1
package.json

@@ -12,10 +12,12 @@
   "author": "leakypixel",
   "author": "leakypixel",
   "license": "ISC",
   "license": "ISC",
   "dependencies": {
   "dependencies": {
+    "app-root-path": "^3.0.0",
     "hasha": "^5.2.2",
     "hasha": "^5.2.2",
     "redis": "^3.1.2",
     "redis": "^3.1.2",
     "restify": "^8.5.1",
     "restify": "^8.5.1",
-    "yup": "^0.32.9"
+    "yup": "^0.32.9",
+    "winston": "^3.3.3"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "eslint": "^7.27.0",
     "eslint": "^7.27.0",

+ 6 - 5
src/easy-api.js

@@ -4,10 +4,11 @@ import yup from 'yup';
 
 
 import { checkReqBody, checkParams } from './modules/check-schema.js';
 import { checkReqBody, checkParams } from './modules/check-schema.js';
 import dbWrapper from './modules/db.js';
 import dbWrapper from './modules/db.js';
+import logger from './modules/logging.js';
 
 
-function registerRoute(db, server) {
+function registerRoute(db, server, log) {
   return function setupRoute(routeSetup) {
   return function setupRoute(routeSetup) {
-    const route = routeSetup({ db, yup });
+    const route = routeSetup({ db, yup, log });
 
 
     if (route.schema) {
     if (route.schema) {
       switch (route.type) {
       switch (route.type) {
@@ -39,17 +40,17 @@ function start(routes, host = '127.0.0.1', port = 8080, dbOpts, serverOpts) {
   const client = redis.createClient(dbOpts);
   const client = redis.createClient(dbOpts);
 
 
   client.on('connect', () => {
   client.on('connect', () => {
-    console.log('connected to db, starting server...');
+    logger.info('connected to db, starting server...');
     const server = restify.createServer(serverOpts);
     const server = restify.createServer(serverOpts);
     const db = dbWrapper(client);
     const db = dbWrapper(client);
-    const setupRoute = registerRoute(db, server);
+    const setupRoute = registerRoute(db, server, logger);
 
 
     routes.forEach(route => {
     routes.forEach(route => {
       setupRoute(route);
       setupRoute(route);
     });
     });
 
 
     server.listen(port, host, () => {
     server.listen(port, host, () => {
-      console.log('%s listening at %s', server.name, server.url);
+      logger.info(`${server.name} listening at ${server.url}`);
     });
     });
   });
   });
 }
 }

+ 3 - 3
src/index.js

@@ -1,4 +1,4 @@
-import start from "./easy-api.js";
-import routes from "./routes/index.js";
+import start from './easy-api.js';
+import routes from './routes/index.js';
 
 
-start(routes, "localhost", 8080, { password: "password123" });
+start(routes, 'localhost', 8080, { password: 'password123' }, { name: 'example-easy-api' });

+ 30 - 0
src/modules/logging.js

@@ -0,0 +1,30 @@
+import winston from 'winston';
+import appRoot from 'app-root-path';
+
+const timestamp = Math.floor(new Date() / 1000);
+
+const options = {
+  file: {
+    level: 'info',
+    filename: `${appRoot}/logs/app-${timestamp}.log`,
+    handleExceptions: true,
+    json: true,
+    maxsize: 5242880, // 5MB
+    maxFiles: 5,
+    colorize: false,
+  },
+  console: {
+    level: 'debug',
+    handleExceptions: true,
+    json: false,
+    colorize: true,
+    format: winston.format.combine(winston.format.colorize(), winston.format.simple()),
+  },
+};
+
+const logger = winston.createLogger({
+  transports: [new winston.transports.File(options.file), new winston.transports.Console(options.console)],
+  exitOnError: false,
+});
+
+export default logger;

+ 7 - 6
src/routes/hello.js

@@ -1,19 +1,20 @@
-function setup({ db, yup }) {
+function setup({ db, yup, log }) {
   return {
   return {
-    type: "get",
-    route: "/hello/:name",
+    type: 'get',
+    route: '/hello/:name',
     handler(req, res, next) {
     handler(req, res, next) {
-      const contentPath = ["visits", req.params.name];
+      const contentPath = ['visits', req.params.name];
       db.get(contentPath, reply => {
       db.get(contentPath, reply => {
         const visits = reply >= 0 ? Number(reply) + 1 : 1;
         const visits = reply >= 0 ? Number(reply) + 1 : 1;
+        log.info(`Visited by ${req.params.name}.`);
         res.send(`hello ${req.params.name}. You have visited ${visits} times.`);
         res.send(`hello ${req.params.name}. You have visited ${visits} times.`);
         db.set(contentPath, visits);
         db.set(contentPath, visits);
         next();
         next();
       });
       });
     },
     },
     schema: yup.object().shape({
     schema: yup.object().shape({
-      name: yup.string().required()
-    })
+      name: yup.string().required(),
+    }),
   };
   };
 }
 }