Skip to content

Commit 2a17af3

Browse files
authored
feat: more correlation fields: service.version, service.environment, service.node.name (#152)
These are retrieved from an active APM agent, if `apmIntegration` is enabled. As well, config options for overriding these (and service.name) have been added. Closes: #121 Closes: #87 Refs: elastic/apm-agent-nodejs#3195
1 parent 0897078 commit 2a17af3

23 files changed

+506
-150
lines changed

docs/morgan.asciidoc

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const app = require('express')()
3232
const morgan = require('morgan')
3333
const ecsFormat = require('@elastic/ecs-morgan-format')
3434
35-
app.use(morgan(ecsFormat())) <1>
35+
app.use(morgan(ecsFormat(/* options */))) <1>
3636
3737
// ...
3838
app.get('/', function (req, res) {
@@ -62,7 +62,7 @@ const app = require('express')()
6262
const morgan = require('morgan')
6363
const ecsFormat = require('@elastic/ecs-morgan-format')
6464
65-
app.use(morgan(ecsFormat()))
65+
app.use(morgan(ecsFormat(/* options */))) <1>
6666
6767
app.get('/', function (req, res) {
6868
res.send('hello, world!')
@@ -73,6 +73,7 @@ app.get('/error', function (req, res, next) {
7373
7474
app.listen(3000)
7575
----
76+
<1> See available options <<morgan-ref,below>>.
7677

7778
Running this script (the full example is https://github.com/elastic/ecs-logging-nodejs/blob/main/loggers/morgan/examples/express.js[here])
7879
and making a request (via `curl -i localhost:3000/`) will produce log output
@@ -161,14 +162,21 @@ again, a `curl -i localhost:3000/error` will yield:
161162

162163
[float]
163164
[[morgan-apm]]
164-
=== Integration with APM Tracing
165+
=== Log Correlation with APM
165166

166-
This ECS log formatter integrates with https://www.elastic.co/apm[Elastic APM] tracing.
167+
This ECS log formatter integrates with https://www.elastic.co/apm[Elastic APM].
167168
If your Node app is using the {apm-node-ref}/intro.html[Node.js Elastic APM Agent],
168-
then fields are added to log records that {ecs-ref}/ecs-tracing.html[identify an active trace] and the configured service name
169-
({ecs-ref}/ecs-service.html["service.name"] and {ecs-ref}/ecs-event.html["event.dataset"]).
170-
These fields allow cross linking between traces and logs in Kibana and support
171-
log anomaly detection.
169+
then a number of fields are added to log records to correlate between APM
170+
services or traces and logging data:
171+
172+
- Log statements (e.g. `logger.info(...)`) called when there is a current
173+
tracing span will include {ecs-ref}/ecs-tracing.html[tracing fields] --
174+
`trace.id`, `transaction.id`.
175+
- A number of service identifier fields determined by or configured on the APM
176+
agent allow cross-linking between services and logs in Kibana --
177+
`service.name`, `service.version`, `service.environment`, `service.node.name`.
178+
- `event.dataset` enables {observability-guide}/inspect-log-anomalies.html[log
179+
rate anomaly detection] in the Elastic Observability app.
172180

173181
For example, running https://github.com/elastic/ecs-logging-nodejs/blob/main/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:
174182

@@ -177,10 +185,12 @@ For example, running https://github.com/elastic/ecs-logging-nodejs/blob/main/log
177185
% node examples/express-with-apm.js | jq .
178186
{
179187
// The same fields as before, plus:
180-
"trace.id": "e097193afa9ac221017b45a1f674601c",
181-
"transaction.id": "c6aa5b47e01bad72",
182188
"service.name": "express-with-elastic-apm",
183-
"event.dataset": "express-with-elastic-apm"
189+
"service.version": "1.1.0",
190+
"service.environment": "development",
191+
"event.dataset": "express-with-elastic-apm",
192+
"trace.id": "116d46f667a7600deed9c41fa015f7de",
193+
"transaction.id": "b84fb72d7bf42866"
184194
}
185195
----
186196

@@ -193,3 +203,24 @@ Integration with Elastic APM can be explicitly disabled via the
193203
----
194204
app.use(morgan(ecsFormat({ apmIntegration: false })))
195205
----
206+
207+
208+
[float]
209+
[[morgan-ref]]
210+
=== Reference
211+
212+
[float]
213+
[[morgan-ref-ecsFormat]]
214+
==== `ecsFormat([options])`
215+
216+
* `options` +{type-object}+ The following options are supported:
217+
** `format` +{type-string}+ A format *name* (e.g. 'combined'), format function (e.g. `morgan.combined`), or a format string (e.g. ':method :url :status'). This is used to format the "message" field. Defaults to `morgan.combined`.
218+
** `convertErr` +{type-boolean}+ Whether to convert a logged `err` field to ECS error fields. *Default:* `true`.
219+
** `apmIntegration` +{type-boolean}+ Whether to enable APM agent integration. *Default:* `true`.
220+
** `serviceName` +{type-string}+ A "service.name" value. If specified this overrides any value from an active APM agent.
221+
** `serviceVersion` +{type-string}+ A "service.version" value. If specified this overrides any value from an active APM agent.
222+
** `serviceEnvironment` +{type-string}+ A "service.environment" value. If specified this overrides any value from an active APM agent.
223+
** `serviceNodeName` +{type-string}+ A "service.node.name" value. If specified this overrides any value from an active APM agent.
224+
** `eventDataset` +{type-string}+ A "event.dataset" value. If specified this overrides the default of using `${serviceVersion}`.
225+
226+
Create a formatter for morgan that emits in ECS Logging format.

docs/pino.asciidoc

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ $ npm install @elastic/ecs-pino-format
2929
const ecsFormat = require('@elastic/ecs-pino-format')
3030
const pino = require('pino')
3131
32-
const log = pino(ecsFormat()) <1>
32+
const log = pino(ecsFormat(/* options */)) <1>
3333
log.info('hi')
3434
log.error({ err: new Error('boom') }, 'oops there is a problem')
3535
// ...
@@ -56,13 +56,13 @@ include::{ecs-repo-dir}/setup.asciidoc[tag=configure-filebeat]
5656
const ecsFormat = require('@elastic/ecs-pino-format')
5757
const pino = require('pino')
5858
59-
const log = pino(ecsFormat()) <1>
59+
const log = pino(ecsFormat(/* options */)) <1>
6060
log.info('Hello world')
6161
6262
const child = log.child({ module: 'foo' })
6363
child.warn('From child')
6464
----
65-
65+
<1> See available options <<pino-ref,below>>.
6666

6767
Running this will produce log output similar to the following:
6868

@@ -205,14 +205,21 @@ etc.
205205

206206
[float]
207207
[[pino-apm]]
208-
=== Integration with APM Tracing
208+
=== Log Correlation with APM
209209

210210
This ECS log formatter integrates with https://www.elastic.co/apm[Elastic APM].
211211
If your Node app is using the {apm-node-ref}/intro.html[Node.js Elastic APM Agent],
212-
then fields are added to log records that {ecs-ref}/ecs-tracing.html[identify an active trace] and the configured service name
213-
({ecs-ref}/ecs-service.html["service.name"] and {ecs-ref}/ecs-event.html["event.dataset"]).
214-
These fields allow cross linking between traces and logs in Kibana and support
215-
log anomaly detection.
212+
then a number of fields are added to log records to correlate between APM
213+
services or traces and logging data:
214+
215+
- Log statements (e.g. `logger.info(...)`) called when there is a current
216+
tracing span will include {ecs-ref}/ecs-tracing.html[tracing fields] --
217+
`trace.id`, `transaction.id`, `span.id`.
218+
- A number of service identifier fields determined by or configured on the APM
219+
agent allow cross-linking between services and logs in Kibana --
220+
`service.name`, `service.version`, `service.environment`, `service.node.name`.
221+
- `event.dataset` enables {observability-guide}/inspect-log-anomalies.html[log
222+
rate anomaly detection] in the Elastic Observability app.
216223

217224
For example, running https://github.com/elastic/ecs-logging-nodejs/blob/main/loggers/pino/examples/http-with-elastic-apm.js[examples/http-with-elastic-apm.js] and `curl -i localhost:3000/` results in a log record with the following:
218225

@@ -221,9 +228,11 @@ For example, running https://github.com/elastic/ecs-logging-nodejs/blob/main/log
221228
% node examples/http-with-elastic-apm.js | jq .
222229
...
223230
"service.name": "http-with-elastic-apm",
231+
"service.version": "1.4.0",
232+
"service.environment": "development",
224233
"event.dataset": "http-with-elastic-apm",
225-
"trace.id": "79de6da334efae17ad43758573d57f1c",
226-
"transaction.id": "8bf944f94b72c54d",
234+
"trace.id": "9f338eae7211b7993b98929046aed21d",
235+
"transaction.id": "2afbef5642cc7a3f",
227236
...
228237
----
229238

@@ -254,3 +263,24 @@ fields passed to `<logger>.child({ ... })`. This means that, even with the
254263
`convertReqRes` option, a call to `<logger>.child({ req })` will *not* convert
255264
that `req` to ECS HTTP fields. This is a slight limitation for users of
256265
https://github.com/pinojs/pino-http[pino-http] which does this.
266+
267+
268+
[float]
269+
[[pino-ref]]
270+
=== Reference
271+
272+
[float]
273+
[[pino-ref-ecsFormat]]
274+
==== `ecsFormat([options])`
275+
276+
* `options` +{type-object}+ The following options are supported:
277+
** `convertErr` +{type-boolean}+ Whether to convert a logged `err` field to ECS error fields. *Default:* `true`.
278+
** `convertReqRes` +{type-boolean}+ Whether to logged `req` and `res` HTTP request and response fields to ECS HTTP, User agent, and URL fields. *Default:* `false`.
279+
** `apmIntegration` +{type-boolean}+ Whether to enable APM agent integration. *Default:* `true`.
280+
** `serviceName` +{type-string}+ A "service.name" value. If specified this overrides any value from an active APM agent.
281+
** `serviceVersion` +{type-string}+ A "service.version" value. If specified this overrides any value from an active APM agent.
282+
** `serviceEnvironment` +{type-string}+ A "service.environment" value. If specified this overrides any value from an active APM agent.
283+
** `serviceNodeName` +{type-string}+ A "service.node.name" value. If specified this overrides any value from an active APM agent.
284+
** `eventDataset` +{type-string}+ A "event.dataset" value. If specified this overrides the default of using `${serviceVersion}`.
285+
286+
Create options for `pino(...)` that configures ECS Logging format output.

docs/winston.asciidoc

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const winston = require('winston')
3030
const ecsFormat = require('@elastic/ecs-winston-format')
3131
3232
const logger = winston.createLogger({
33-
format: ecsFormat(), <1>
33+
format: ecsFormat(/* options */), <1>
3434
transports: [
3535
new winston.transports.Console()
3636
]
@@ -63,7 +63,7 @@ const ecsFormat = require('@elastic/ecs-winston-format')
6363
6464
const logger = winston.createLogger({
6565
level: 'info',
66-
format: ecsFormat(), <1>
66+
format: ecsFormat(/* options */), <1>
6767
transports: [
6868
new winston.transports.Console()
6969
]
@@ -72,6 +72,7 @@ const logger = winston.createLogger({
7272
logger.info('hi')
7373
logger.error('oops there is a problem', { foo: 'bar' })
7474
----
75+
<1> See available options <<winston-ref,below>>.
7576

7677
Running this script (available https://github.com/elastic/ecs-logging-nodejs/blob/main/loggers/winston/examples/basic.js[here]) will produce log output similar to the following:
7778

@@ -226,14 +227,21 @@ For https://github.com/elastic/ecs-logging-nodejs/blob/main/loggers/winston/exam
226227

227228
[float]
228229
[[winston-apm]]
229-
=== Integration with APM Tracing
230+
=== Log Correlation with APM
230231

231232
This ECS log formatter integrates with https://www.elastic.co/apm[Elastic APM].
232233
If your Node app is using the {apm-node-ref}/intro.html[Node.js Elastic APM Agent],
233-
then fields are added to log records that {ecs-ref}/ecs-tracing.html[identify an active trace] and the configured service name
234-
({ecs-ref}/ecs-service.html["service.name"] and {ecs-ref}/ecs-event.html["event.dataset"]).
235-
These fields allow cross linking between traces and logs in Kibana and support
236-
log anomaly detection.
234+
then a number of fields are added to log records to correlate between APM
235+
services or traces and logging data:
236+
237+
- Log statements (e.g. `logger.info(...)`) called when there is a current
238+
tracing span will include {ecs-ref}/ecs-tracing.html[tracing fields] --
239+
`trace.id`, `transaction.id`, `span.id`.
240+
- A number of service identifier fields determined by or configured on the APM
241+
agent allow cross-linking between services and logs in Kibana --
242+
`service.name`, `service.version`, `service.environment`, `service.node.name`.
243+
- `event.dataset` enables {observability-guide}/inspect-log-anomalies.html[log
244+
rate anomaly detection] in the Elastic Observability app.
237245

238246
For example, running https://github.com/elastic/ecs-logging-nodejs/blob/main/loggers/winston/examples/http-with-elastic-apm.js[examples/http-with-elastic-apm.js] and `curl -i localhost:3000/` results in a log record with the following:
239247

@@ -242,7 +250,9 @@ For example, running https://github.com/elastic/ecs-logging-nodejs/blob/main/log
242250
% node examples/http-with-elastic-apm.js | jq .
243251
...
244252
"service.name": "http-with-elastic-apm",
245-
"event.dataset": "http-with-elastic-apm",
253+
"service.version": "1.4.0",
254+
"service.environment": "development",
255+
"event.dataset": "http-with-elastic-apm"
246256
"trace.id": "7fd75f0f33ff49aba85d060b46dcad7e",
247257
"transaction.id": "6c97c7c1b468fa05"
248258
}
@@ -261,3 +271,22 @@ const logger = winston.createLogger({
261271
})
262272
----
263273

274+
[float]
275+
[[winston-ref]]
276+
=== Reference
277+
278+
[float]
279+
[[winston-ref-ecsFormat]]
280+
==== `ecsFormat([options])`
281+
282+
* `options` +{type-object}+ The following options are supported:
283+
** `convertErr` +{type-boolean}+ Whether to convert a logged `err` field to ECS error fields. *Default:* `true`.
284+
** `convertReqRes` +{type-boolean}+ Whether to logged `req` and `res` HTTP request and response fields to ECS HTTP, User agent, and URL fields. *Default:* `false`.
285+
** `apmIntegration` +{type-boolean}+ Whether to enable APM agent integration. *Default:* `true`.
286+
** `serviceName` +{type-string}+ A "service.name" value. If specified this overrides any value from an active APM agent.
287+
** `serviceVersion` +{type-string}+ A "service.version" value. If specified this overrides any value from an active APM agent.
288+
** `serviceEnvironment` +{type-string}+ A "service.environment" value. If specified this overrides any value from an active APM agent.
289+
** `serviceNodeName` +{type-string}+ A "service.node.name" value. If specified this overrides any value from an active APM agent.
290+
** `eventDataset` +{type-string}+ A "event.dataset" value. If specified this overrides the default of using `${serviceVersion}`.
291+
292+
Create a formatter for winston that emits in ECS Logging format.

loggers/morgan/CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,22 @@
22

33
## Unreleased
44

5+
- Add `service.version`, `service.environment`, and `service.node.name` log
6+
correlation fields, automatically inferred from an active APM agent. As
7+
well, the following `ecsFormat` configuration options have been added for
8+
overriding these and existing correlation fields: `serviceName`,
9+
`serviceVersion`, `serviceEnvironment`, `serviceNodeName`.
10+
(https://github.com/elastic/apm-agent-nodejs/issues/3195,
11+
https://github.com/elastic/ecs-logging-nodejs/issues/121,
12+
https://github.com/elastic/ecs-logging-nodejs/issues/87)
13+
514
- Change to adding dotted field names (`"ecs.version": "1.6.0"`), rather than
615
namespaced fields (`"ecs": {"version": "1.6.0"}`) for most fields. This is
716
supported by the ecs-logging spec, and arguably preferred in the ECS logging
817
docs. It is also what the ecs-logging-java libraries do. The resulting output
918
is slightly shorter, and accidental collisions with user fields is less
1019
likely.
20+
1121
- Stop adding ".log" suffix to `event.dataset` field.
1222
([#95](https://github.com/elastic/ecs-logging-nodejs/issues/95))
1323

loggers/morgan/README.md

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const app = require('express')()
2828
const morgan = require('morgan')
2929
const ecsFormat = require('@elastic/ecs-morgan-format')
3030

31-
app.use(morgan(ecsFormat()))
31+
app.use(morgan(ecsFormat(/* options */)))
3232

3333
app.get('/', function (req, res) {
3434
res.send('hello, world!')
@@ -43,18 +43,16 @@ produce log output similar to the following:
4343
```sh
4444
% node examples/express.js | jq . # piping to jq for pretty-printing
4545
{
46-
"@timestamp": "2021-01-16T00:03:23.279Z",
46+
"@timestamp": "2023-10-16T22:00:33.782Z",
4747
"log.level": "info",
48-
"message": "::1 - - [16/Jan/2021:00:03:23 +0000] \"GET / HTTP/1.1\" 200 13 \"-\" \"curl/7.64.1\"",
49-
"ecs": {
50-
"version": "1.6.0"
51-
},
48+
"message": "::ffff:127.0.0.1 - - [16/Oct/2023:22:00:33 +0000] \"GET / HTTP/1.1\" 200 13 \"-\" \"curl/8.1.2\"",
5249
"http": {
5350
"version": "1.1",
5451
"request": {
5552
"method": "GET",
5653
"headers": {
5754
"host": "localhost:3000",
55+
"user-agent": "curl/8.1.2",
5856
"accept": "*/*"
5957
}
6058
},
@@ -63,6 +61,7 @@ produce log output similar to the following:
6361
"headers": {
6462
"x-powered-by": "Express",
6563
"content-type": "text/html; charset=utf-8",
64+
"content-length": "13",
6665
"etag": "W/\"d-HwnTDHB9U/PRbFMN1z1wps51lqk\""
6766
},
6867
"body": {
@@ -75,9 +74,15 @@ produce log output similar to the following:
7574
"domain": "localhost",
7675
"full": "http://localhost:3000/"
7776
},
77+
"client": {
78+
"address": "::ffff:127.0.0.1",
79+
"ip": "::ffff:127.0.0.1",
80+
"port": 60455
81+
},
7882
"user_agent": {
79-
"original": "curl/7.64.1"
80-
}
83+
"original": "curl/8.1.2"
84+
},
85+
"ecs.version": "1.6.0"
8186
}
8287
```
8388

0 commit comments

Comments
 (0)