diff --git a/.dockerignore b/.dockerignore index 5cb0969..375b896 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,11 +1,9 @@ # Github .github .gitignore -docs +docs *.md -Dockerfile -Dockerfile.local -docker-compose.yml +docker-compose/* # Logs logs diff --git a/README.md b/README.md index 26700d6..5a02dd3 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,9 @@ Available: * [Combine custom actions](#Combinecustomactions) * [Change default Queries/Request commands](#ChangedefaultQueriesRequestcommands) * [Loggers](#Loggers) + * [Format](#Format) * [Seq](#Seq) + * [ELK](#ELK) * [Setting up](#Settingup) * [Docker](#Docker) * [Docker-Compose](#Docker-Compose) @@ -243,11 +245,20 @@ HTTP/1.1 401 Unauthorized | Environment | CLI | Default | |------------------------------------|------------------------------------|--------------------| | LOGS__APP | --logs:app | `echo-server` | -| LOGS__LEVEL | --logs:level | `debug` | +| LOGS__LEVEL | --logs:level | `debug` | +| LOGS__FORMAT | --logs:format | `default` | + +### Format + +| LOG FORMAT | DESCRIPTION | +|-------------------|-----------------------------------------------------------------------------| +| default | Combine `line` & `object` | +| line | Simple `Fri, 22 Jan 2021 10:45:20 GMT | [GET] - http://localhost:8080/path` | +| object | JSON `{ "host": {}, http: {}, request: {}}` | ### Seq -![seq](https://ealenn.github.io/Echo-Server/assets/images/seq.png) +[Full example](https://github.com/Ealenn/Echo-Server/tree/master/docker-compose) - [Documentation](https://ealenn.github.io/Echo-Server/pages/quick-start/docker-compose.html) | Environment | CLI | Default | |------------------------------------|------------------------------------|--------------------| @@ -256,6 +267,10 @@ HTTP/1.1 401 Unauthorized | LOGS__SEQ__KEY | --logs:seq:key | ` ` | | LOGS__SEQ__LEVEL | --logs:seq:level | `info` | +### ELK + +[Full example](https://github.com/Ealenn/Echo-Server/tree/master/docker-compose) - [Documentation](https://ealenn.github.io/Echo-Server/pages/quick-start/docker-compose.html) + ## Setting up ### Docker @@ -285,7 +300,6 @@ services: ```yaml version: "3" - services: echo: image: ealen/echo-server diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..673a07d --- /dev/null +++ b/codecov.yml @@ -0,0 +1,7 @@ +coverage: + range: 90..100 + round: down + precision: 2 +ignore: + - "test/*" + - "src/middlewares/logMiddleware.js" \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index b585083..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,28 +0,0 @@ -version: "3" - -services: - echo: - build: - context: . - dockerfile: Dockerfile.local - environment: - PORT: 80 - LOGS__SEQ__ENABLED: "true" - LOGS__SEQ__SERVER: "http://seq:5341" - ports: - - 8080:80 - networks: - - backend - - seq: - image: datalust/seq:latest - environment: - ACCEPT_EULA: "Y" - ports: - - 8081:80 - - 5341:5341 - networks: - - backend - -networks: - backend: \ No newline at end of file diff --git a/Dockerfile.local b/docker-compose/Dockerfile.local similarity index 100% rename from Dockerfile.local rename to docker-compose/Dockerfile.local diff --git a/docker-compose/ELK/docker-compose.yml b/docker-compose/ELK/docker-compose.yml new file mode 100644 index 0000000..e9aca50 --- /dev/null +++ b/docker-compose/ELK/docker-compose.yml @@ -0,0 +1,48 @@ +version: "3" +services: + # ---------------------------------- + # ECHO-SERVER + # ---------------------------------- + echo: + build: + context: ../../ + dockerfile: docker-compose/Dockerfile.local + restart: unless-stopped + logging: + driver: syslog + options: + syslog-address: "tcp://localhost:8089" + environment: + - "LOGS__FORMAT=object" + depends_on: + - logstash + ports: + - 3000:80 + + # ---------------------------------- + # ELK + # ---------------------------------- + elasticsearch: + image: elasticsearch:7.7.0 + hostname: elasticsearch + restart: unless-stopped + environment: + - "discovery.type=single-node" + kibana: + image: kibana:7.7.0 + hostname: kibana + restart: unless-stopped + depends_on: + - elasticsearch + ports: + - 3010:5601 + logstash: + image: logstash:7.7.0 + hostname: logstash + restart: unless-stopped + volumes: + - ./logstash:/usr/share/logstash/pipeline/ + depends_on: + - elasticsearch + ports: + - 8089:8089 diff --git a/docker-compose/ELK/logstash/logstash.conf b/docker-compose/ELK/logstash/logstash.conf new file mode 100755 index 0000000..f2a9dd6 --- /dev/null +++ b/docker-compose/ELK/logstash/logstash.conf @@ -0,0 +1,9 @@ +input { + tcp { + port => 8089 + } +} + +output { + elasticsearch { hosts => ["elasticsearch:9200"] } +} \ No newline at end of file diff --git a/docker-compose/SEQ/docker-compose.yml b/docker-compose/SEQ/docker-compose.yml new file mode 100644 index 0000000..8a14ea2 --- /dev/null +++ b/docker-compose/SEQ/docker-compose.yml @@ -0,0 +1,27 @@ +version: "3" +services: + # ---------------------------------- + # ECHO-SERVER + # ---------------------------------- + echo: + build: + context: ../../ + dockerfile: ../Dockerfile.local + restart: unless-stopped + environment: + PORT: 80 + LOGS__SEQ__ENABLED: "true" + LOGS__SEQ__SERVER: "http://seq:5341" + ports: + - 3000:80 + + # ---------------------------------- + # SEQ + # ---------------------------------- + seq: + image: datalust/seq:latest + restart: unless-stopped + environment: + ACCEPT_EULA: "Y" + ports: + - 3010:80 diff --git a/docs/pages/configuration/loggers.md b/docs/pages/configuration/loggers.md index 8a8feed..6f0b3ba 100644 --- a/docs/pages/configuration/loggers.md +++ b/docs/pages/configuration/loggers.md @@ -23,6 +23,15 @@ nav_order: 2 | LOGS__IGNORE__PING | --logs:ignore:ping | `false` | | LOGS__APP | --logs:app | `echo-server` | | LOGS__LEVEL | --logs:level | `debug` | +| LOGS__FORMAT | --logs:format | `default` | + +### Format + +| LOG FORMAT | DESCRIPTION | +|-------------------|-----------------------------------------------------------------------------| +| default | Combine `line` and `object` | +| line | Simple `Fri, 22 Jan 2021 10:45:20 GMT | [GET] - http://localhost:8080/path` | +| object | JSON `{ "host": {}, http: {}, request: {}}` | ## Seq diff --git a/docs/pages/quick-start/docker-compose.md b/docs/pages/quick-start/docker-compose.md index d9f96a0..f5bdea0 100644 --- a/docs/pages/quick-start/docker-compose.md +++ b/docs/pages/quick-start/docker-compose.md @@ -51,26 +51,106 @@ services: [More information](https://ealenn.github.io/Echo-Server/pages/configuration/loggers) +### Seq + ```yaml version: "3" services: + # ---------------------------------- + # ECHO-SERVER + # ---------------------------------- echo: image: ealen/echo-server:{{ site.github.releases[0].tag_name }} - environment: + restart: unless-stopped + environment: PORT: 80 LOGS__SEQ__ENABLED: "true" LOGS__SEQ__SERVER: "http://seq:5341" - ports: + ports: - 3000:80 + # ---------------------------------- + # SEQ + # ---------------------------------- seq: - image: datalust/seq:{{ site.github.releases[0].tag_name }} - environment: + image: datalust/seq:latest + restart: unless-stopped + environment: ACCEPT_EULA: "Y" ports: - 3010:80 ``` +> - Echo-Server : [http://localhost:3000](http://localhost:3000) +> - Seq : [http://localhost:3010](http://localhost:3010) + +### ELK + +```conf +# ./logstash/logstash.conf +input { + tcp { + port => 8089 + } +} + +output { + elasticsearch { hosts => ["elasticsearch:9200"] } +} +``` + +```yaml +version: "3" +services: + # ---------------------------------- + # ECHO-SERVER + # ---------------------------------- + echo: + image: ealen/echo-server:{{ site.github.releases[0].tag_name }} + restart: unless-stopped + logging: + driver: syslog + options: + syslog-address: "tcp://localhost:8089" + environment: + - "LOGS__FORMAT=object" + depends_on: + - logstash + ports: + - 3000:80 + + # ---------------------------------- + # ELK + # ---------------------------------- + elasticsearch: + image: elasticsearch:7.7.0 + hostname: elasticsearch + restart: unless-stopped + environment: + - "discovery.type=single-node" + kibana: + image: kibana:7.7.0 + hostname: kibana + restart: unless-stopped + depends_on: + - elasticsearch + ports: + - 3010:5601 + logstash: + image: logstash:7.7.0 + hostname: logstash + restart: unless-stopped + volumes: + - ./logstash:/usr/share/logstash/pipeline/ + depends_on: + - elasticsearch + ports: + - 8089:8089 +``` + +> - Echo-Server : [http://localhost:3000](http://localhost:3000) +> - Kibana : [http://localhost:3010](http://localhost:3010) + ## Examples {% include_relative includes/section-examples.md host="localhost:3000" %} \ No newline at end of file diff --git a/src/global.json b/src/global.json index 939ba20..4e884c6 100644 --- a/src/global.json +++ b/src/global.json @@ -3,6 +3,7 @@ "logs": { "app": "echo-server", "level": "debug", + "format": "default", "ignore": { "ping": false }, diff --git a/src/middlewares/logMiddleware.js b/src/middlewares/logMiddleware.js index 05f19dd..52aaac9 100644 --- a/src/middlewares/logMiddleware.js +++ b/src/middlewares/logMiddleware.js @@ -25,12 +25,28 @@ const log = bunyan.createLogger({ module.exports = (req, res, next) => { if (req.originalUrl != "/ping" || !config.get('logs:ignore:ping')) { - log.info({ - host: require('../response/host')(req), - http: require('../response/http')(req), - request: require('../response/request')(req), - environment: require('../response/environment')(req) - }, `${new Date().toUTCString()} | [${req.method}] - ${req.protocol}://${req.get('host')}${req.originalUrl}`); + switch (config.get('logs:format')) + { + case "line": + log.info(`${new Date().toUTCString()} | [${req.method}] - ${req.protocol}://${req.get('host')}${req.originalUrl}`); + break; + case "object": + log.info({ + host: require('../response/host')(req), + http: require('../response/http')(req), + request: require('../response/request')(req), + environment: require('../response/environment')(req) + }); + break; + default: + log.info({ + host: require('../response/host')(req), + http: require('../response/http')(req), + request: require('../response/request')(req), + environment: require('../response/environment')(req) + }, `${new Date().toUTCString()} | [${req.method}] - ${req.protocol}://${req.get('host')}${req.originalUrl}`); + break; + } } next(); } \ No newline at end of file diff --git a/test/logs.js b/test/logs.js new file mode 100644 index 0000000..676c87a --- /dev/null +++ b/test/logs.js @@ -0,0 +1,74 @@ +const assert = require('assert'); +const request = require('supertest'); + +process.env.LOGS__LEVEL = "error"; + +const availableConfiguration = ["default", "line", "object"]; + +availableConfiguration.forEach(configuration => { + process.env.LOGS__FORMAT = configuration; + describe('Logs with ' + configuration, function () { + var server; + beforeEach(function () { + server = require('../src/app'); + }); + afterEach(function () { + server.close(); + }); + it('GET', function test(done) { + request(server) + .get('/') + .expect(function (res) { + assert.strictEqual(res.body.http.method, 'GET') + assert.strictEqual(res.body.http.protocol, 'http') + assert.strictEqual(res.body.http.originalUrl, '/') + assert.strictEqual(res.body.http.baseUrl, '') + }) + .expect(200, done); + }); + it('POST', function test(done) { + request(server) + .post('/') + .expect(function (res) { + assert.strictEqual(res.body.http.method, 'POST') + assert.strictEqual(res.body.http.protocol, 'http') + assert.strictEqual(res.body.http.originalUrl, '/') + assert.strictEqual(res.body.http.baseUrl, '') + }) + .expect(200, done); + }); + it('PUT', function test(done) { + request(server) + .put('/') + .expect(function (res) { + assert.strictEqual(res.body.http.method, 'PUT') + assert.strictEqual(res.body.http.protocol, 'http') + assert.strictEqual(res.body.http.originalUrl, '/') + assert.strictEqual(res.body.http.baseUrl, '') + }) + .expect(200, done); + }); + it('PATCH', function test(done) { + request(server) + .patch('/') + .expect(function (res) { + assert.strictEqual(res.body.http.method, 'PATCH') + assert.strictEqual(res.body.http.protocol, 'http') + assert.strictEqual(res.body.http.originalUrl, '/') + assert.strictEqual(res.body.http.baseUrl, '') + }) + .expect(200, done); + }); + it('DELETE', function test(done) { + request(server) + .delete('/') + .expect(function (res) { + assert.strictEqual(res.body.http.method, 'DELETE') + assert.strictEqual(res.body.http.protocol, 'http') + assert.strictEqual(res.body.http.originalUrl, '/') + assert.strictEqual(res.body.http.baseUrl, '') + }) + .expect(200, done); + }); + }); +});