|
| 1 | +[[morgan]] |
| 2 | +== ECS Logging with Morgan |
| 3 | + |
| 4 | +This Node.js package provides a formatter for the https://github.com/expressjs/morgan#readme[morgan] |
| 5 | +logging middleware -- commonly used with Express -- compatible with |
| 6 | +{ecs-logging-ref}/intro.html[Elastic Common Schema (ECS) logging]. |
| 7 | +In combination with the https://www.elastic.co/beats/filebeat[Filebeat] shipper, |
| 8 | +you can https://www.elastic.co/log-monitoring[monitor all your logs] in one |
| 9 | +place in the Elastic Stack. |
| 10 | + |
| 11 | + |
| 12 | +[float] |
| 13 | +=== Setup |
| 14 | + |
| 15 | +[float] |
| 16 | +[[morgan-setup-step-1]] |
| 17 | +==== Step 1: Install |
| 18 | + |
| 19 | +[source,cmd] |
| 20 | +---- |
| 21 | +$ npm install @elastic/ecs-morgan-format |
| 22 | +---- |
| 23 | + |
| 24 | + |
| 25 | +[float] |
| 26 | +[[morgan-setup-step-2]] |
| 27 | +==== Step 2: Configure |
| 28 | + |
| 29 | +[source,js] |
| 30 | +---- |
| 31 | +const app = require('express')() |
| 32 | +const morgan = require('morgan') |
| 33 | +const ecsFormat = require('@elastic/ecs-morgan-format') |
| 34 | +
|
| 35 | +app.use(morgan(ecsFormat())) <1> |
| 36 | +
|
| 37 | +// ... |
| 38 | +app.get('/', function (req, res) { |
| 39 | + res.send('hello, world!') |
| 40 | +}) |
| 41 | +app.listen(3000) |
| 42 | +---- |
| 43 | +<1> Pass the ECS formatter to `morgan()`. |
| 44 | + |
| 45 | + |
| 46 | +[float] |
| 47 | +[[morgan-setup-step-3]] |
| 48 | +==== Step 3: Configure Filebeat |
| 49 | + |
| 50 | +The best way to collect the logs once they are ECS-formatted is with {filebeat-ref}[Filebeat]: |
| 51 | + |
| 52 | +include::{ecs-repo-dir}/setup.asciidoc[tag=configure-filebeat] |
| 53 | + |
| 54 | + |
| 55 | +[float] |
| 56 | +[[morgan-usage]] |
| 57 | +=== Usage |
| 58 | + |
| 59 | +[source,js] |
| 60 | +---- |
| 61 | +const app = require('express')() |
| 62 | +const morgan = require('morgan') |
| 63 | +const ecsFormat = require('@elastic/ecs-morgan-format') |
| 64 | +
|
| 65 | +app.use(morgan(ecsFormat())) |
| 66 | +
|
| 67 | +app.get('/', function (req, res) { |
| 68 | + res.send('hello, world!') |
| 69 | +}) |
| 70 | +app.get('/error', function (req, res, next) { |
| 71 | + next(new Error('boom')) |
| 72 | +}) |
| 73 | +
|
| 74 | +app.listen(3000) |
| 75 | +---- |
| 76 | + |
| 77 | +Running this script (the full example is https://github.com/elastic/ecs-logging-nodejs/blob/master/loggers/morgan/examples/express.js[here]) |
| 78 | +and making a request (via `curl -i localhost:3000/`) will produce log output |
| 79 | +similar to the following: |
| 80 | + |
| 81 | +[source,cmd] |
| 82 | +---- |
| 83 | +% node examples/express.js | jq . # piping to jq for pretty-printing |
| 84 | +{ |
| 85 | + "@timestamp": "2021-01-16T00:03:23.279Z", |
| 86 | + "log.level": "info", |
| 87 | + "message": "::1 - - [16/Jan/2021:00:03:23 +0000] \"GET / HTTP/1.1\" 200 13 \"-\" \"curl/7.64.1\"", |
| 88 | + "ecs": { |
| 89 | + "version": "1.5.0" |
| 90 | + }, |
| 91 | + "http": { |
| 92 | + "version": "1.1", |
| 93 | + "request": { |
| 94 | + "method": "get", |
| 95 | + "headers": { |
| 96 | + "host": "localhost:3000", |
| 97 | + "accept": "*/*" |
| 98 | + } |
| 99 | + }, |
| 100 | + "response": { |
| 101 | + "status_code": 200, |
| 102 | + "headers": { |
| 103 | + "x-powered-by": "Express", |
| 104 | + "content-type": "text/html; charset=utf-8", |
| 105 | + "etag": "W/\"d-HwnTDHB9U/PRbFMN1z1wps51lqk\"" |
| 106 | + }, |
| 107 | + "body": { |
| 108 | + "bytes": 13 |
| 109 | + } |
| 110 | + } |
| 111 | + }, |
| 112 | + "url": { |
| 113 | + "path": "/", |
| 114 | + "domain": "localhost", |
| 115 | + "full": "http://localhost:3000/" |
| 116 | + }, |
| 117 | + "user_agent": { |
| 118 | + "original": "curl/7.64.1" |
| 119 | + } |
| 120 | +} |
| 121 | +---- |
| 122 | + |
| 123 | +[float] |
| 124 | +[[morgan-format-options]] |
| 125 | +=== Format Options |
| 126 | + |
| 127 | +You can pass any https://github.com/expressjs/morgan#morganformat-options[`format` argument] |
| 128 | +you would normally pass to `morgan()`, and the log "message" field will use the |
| 129 | +specified format. The default is https://github.com/expressjs/morgan#combined[`combined`]. |
| 130 | + |
| 131 | +[source,js] |
| 132 | +---- |
| 133 | +const app = require('express')() |
| 134 | +const morgan = require('morgan') |
| 135 | +const ecsFormat = require('@elastic/ecs-morgan-format') |
| 136 | +
|
| 137 | +app.use(morgan(ecsFormat('tiny'))) <1> |
| 138 | +// ... |
| 139 | +---- |
| 140 | + |
| 141 | +[float] |
| 142 | +[[morgan-log-level]] |
| 143 | +=== log.level |
| 144 | + |
| 145 | +The `log.level` field will be "error" for response codes >= 500, otherwise |
| 146 | +"info". For example, running https://github.com/elastic/ecs-logging-nodejs/blob/master/loggers/morgan/examples/express.js[examples/express.js] |
| 147 | +again, a `curl -i localhost:3000/error` will yield: |
| 148 | + |
| 149 | +[source,cmd] |
| 150 | +---- |
| 151 | +% node examples/express.js | jq . |
| 152 | +{ |
| 153 | + "@timestamp": "2021-01-18T17:52:12.810Z", |
| 154 | + "log.level": "error", |
| 155 | + "message": "::1 - - [18/Jan/2021:17:52:12 +0000] \"GET /error HTTP/1.1\" 500 1416 \"-\" \"curl/7.64.1\"", |
| 156 | + "http": { |
| 157 | + "response": { |
| 158 | + "status_code": 500, |
| 159 | + ... |
| 160 | +---- |
| 161 | + |
| 162 | + |
| 163 | +[float] |
| 164 | +[[morgan-apm]] |
| 165 | +=== Integration with APM Tracing |
| 166 | + |
| 167 | +This ECS log formatter integrates with https://www.elastic.co/apm[Elastic APM] tracing. |
| 168 | +If your Node app is using the {apm-node-ref}/intro.html[Node.js Elastic APM Agent], |
| 169 | +then fields are added to log records that {ecs-ref}/ecs-tracing.html[identify an active trace] and the configured service name |
| 170 | +({ecs-ref}/ecs-service.html#field-service-name["service.name"] and |
| 171 | +{ecs-ref}/ecs-event.html#field-event-dataset["event.dataset"]). |
| 172 | +These fields allow cross linking between traces and logs in Kibana and support |
| 173 | +log anomaly detection. |
| 174 | + |
| 175 | +For example, running https://github.com/elastic/ecs-logging-nodejs/blob/master/loggers/morgan/examples/express-with-apm.js[examples/express-with-apm.js] and `curl -i localhost:3000/` results in a log record with the following: |
| 176 | + |
| 177 | +[source,cmd] |
| 178 | +---- |
| 179 | +% node examples/express-with-apm.js | jq . |
| 180 | +{ |
| 181 | + ... |
| 182 | + "event": { |
| 183 | + "dataset": "express-with-elastic-apm.log" |
| 184 | + }, |
| 185 | + "trace": { |
| 186 | + "id": "e097193afa9ac221017b45a1f674601c" |
| 187 | + }, |
| 188 | + "transaction": { |
| 189 | + "id": "c6aa5b47e01bad72" |
| 190 | + }, |
| 191 | + "service": { |
| 192 | + "name": "express-with-elastic-apm" |
| 193 | + } |
| 194 | +} |
| 195 | +---- |
| 196 | + |
| 197 | +These IDs match trace data reported by the APM agent. |
0 commit comments