Skip to content

Commit

Permalink
feat: more correlation fields: service.version, service.environment, …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
trentm authored Oct 17, 2023
1 parent 0897078 commit 2a17af3
Show file tree
Hide file tree
Showing 23 changed files with 506 additions and 150 deletions.
53 changes: 42 additions & 11 deletions docs/morgan.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const app = require('express')()
const morgan = require('morgan')
const ecsFormat = require('@elastic/ecs-morgan-format')
app.use(morgan(ecsFormat())) <1>
app.use(morgan(ecsFormat(/* options */))) <1>
// ...
app.get('/', function (req, res) {
Expand Down Expand Up @@ -62,7 +62,7 @@ const app = require('express')()
const morgan = require('morgan')
const ecsFormat = require('@elastic/ecs-morgan-format')
app.use(morgan(ecsFormat()))
app.use(morgan(ecsFormat(/* options */))) <1>
app.get('/', function (req, res) {
res.send('hello, world!')
Expand All @@ -73,6 +73,7 @@ app.get('/error', function (req, res, next) {
app.listen(3000)
----
<1> See available options <<morgan-ref,below>>.

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

[float]
[[morgan-apm]]
=== Integration with APM Tracing
=== Log Correlation with APM

This ECS log formatter integrates with https://www.elastic.co/apm[Elastic APM] tracing.
This ECS log formatter integrates with https://www.elastic.co/apm[Elastic APM].
If your Node app is using the {apm-node-ref}/intro.html[Node.js Elastic APM Agent],
then fields are added to log records that {ecs-ref}/ecs-tracing.html[identify an active trace] and the configured service name
({ecs-ref}/ecs-service.html["service.name"] and {ecs-ref}/ecs-event.html["event.dataset"]).
These fields allow cross linking between traces and logs in Kibana and support
log anomaly detection.
then a number of fields are added to log records to correlate between APM
services or traces and logging data:

- Log statements (e.g. `logger.info(...)`) called when there is a current
tracing span will include {ecs-ref}/ecs-tracing.html[tracing fields] --
`trace.id`, `transaction.id`.
- A number of service identifier fields determined by or configured on the APM
agent allow cross-linking between services and logs in Kibana --
`service.name`, `service.version`, `service.environment`, `service.node.name`.
- `event.dataset` enables {observability-guide}/inspect-log-anomalies.html[log
rate anomaly detection] in the Elastic Observability app.

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:

Expand All @@ -177,10 +185,12 @@ For example, running https://github.com/elastic/ecs-logging-nodejs/blob/main/log
% node examples/express-with-apm.js | jq .
{
// The same fields as before, plus:
"trace.id": "e097193afa9ac221017b45a1f674601c",
"transaction.id": "c6aa5b47e01bad72",
"service.name": "express-with-elastic-apm",
"event.dataset": "express-with-elastic-apm"
"service.version": "1.1.0",
"service.environment": "development",
"event.dataset": "express-with-elastic-apm",
"trace.id": "116d46f667a7600deed9c41fa015f7de",
"transaction.id": "b84fb72d7bf42866"
}
----

Expand All @@ -193,3 +203,24 @@ Integration with Elastic APM can be explicitly disabled via the
----
app.use(morgan(ecsFormat({ apmIntegration: false })))
----


[float]
[[morgan-ref]]
=== Reference

[float]
[[morgan-ref-ecsFormat]]
==== `ecsFormat([options])`

* `options` +{type-object}+ The following options are supported:
** `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`.
** `convertErr` +{type-boolean}+ Whether to convert a logged `err` field to ECS error fields. *Default:* `true`.
** `apmIntegration` +{type-boolean}+ Whether to enable APM agent integration. *Default:* `true`.
** `serviceName` +{type-string}+ A "service.name" value. If specified this overrides any value from an active APM agent.
** `serviceVersion` +{type-string}+ A "service.version" value. If specified this overrides any value from an active APM agent.
** `serviceEnvironment` +{type-string}+ A "service.environment" value. If specified this overrides any value from an active APM agent.
** `serviceNodeName` +{type-string}+ A "service.node.name" value. If specified this overrides any value from an active APM agent.
** `eventDataset` +{type-string}+ A "event.dataset" value. If specified this overrides the default of using `${serviceVersion}`.

Create a formatter for morgan that emits in ECS Logging format.
50 changes: 40 additions & 10 deletions docs/pino.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ $ npm install @elastic/ecs-pino-format
const ecsFormat = require('@elastic/ecs-pino-format')
const pino = require('pino')
const log = pino(ecsFormat()) <1>
const log = pino(ecsFormat(/* options */)) <1>
log.info('hi')
log.error({ err: new Error('boom') }, 'oops there is a problem')
// ...
Expand All @@ -56,13 +56,13 @@ include::{ecs-repo-dir}/setup.asciidoc[tag=configure-filebeat]
const ecsFormat = require('@elastic/ecs-pino-format')
const pino = require('pino')
const log = pino(ecsFormat()) <1>
const log = pino(ecsFormat(/* options */)) <1>
log.info('Hello world')
const child = log.child({ module: 'foo' })
child.warn('From child')
----

<1> See available options <<pino-ref,below>>.

Running this will produce log output similar to the following:

Expand Down Expand Up @@ -205,14 +205,21 @@ etc.

[float]
[[pino-apm]]
=== Integration with APM Tracing
=== Log Correlation with APM

This ECS log formatter integrates with https://www.elastic.co/apm[Elastic APM].
If your Node app is using the {apm-node-ref}/intro.html[Node.js Elastic APM Agent],
then fields are added to log records that {ecs-ref}/ecs-tracing.html[identify an active trace] and the configured service name
({ecs-ref}/ecs-service.html["service.name"] and {ecs-ref}/ecs-event.html["event.dataset"]).
These fields allow cross linking between traces and logs in Kibana and support
log anomaly detection.
then a number of fields are added to log records to correlate between APM
services or traces and logging data:

- Log statements (e.g. `logger.info(...)`) called when there is a current
tracing span will include {ecs-ref}/ecs-tracing.html[tracing fields] --
`trace.id`, `transaction.id`, `span.id`.
- A number of service identifier fields determined by or configured on the APM
agent allow cross-linking between services and logs in Kibana --
`service.name`, `service.version`, `service.environment`, `service.node.name`.
- `event.dataset` enables {observability-guide}/inspect-log-anomalies.html[log
rate anomaly detection] in the Elastic Observability app.

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:

Expand All @@ -221,9 +228,11 @@ For example, running https://github.com/elastic/ecs-logging-nodejs/blob/main/log
% node examples/http-with-elastic-apm.js | jq .
...
"service.name": "http-with-elastic-apm",
"service.version": "1.4.0",
"service.environment": "development",
"event.dataset": "http-with-elastic-apm",
"trace.id": "79de6da334efae17ad43758573d57f1c",
"transaction.id": "8bf944f94b72c54d",
"trace.id": "9f338eae7211b7993b98929046aed21d",
"transaction.id": "2afbef5642cc7a3f",
...
----

Expand Down Expand Up @@ -254,3 +263,24 @@ fields passed to `<logger>.child({ ... })`. This means that, even with the
`convertReqRes` option, a call to `<logger>.child({ req })` will *not* convert
that `req` to ECS HTTP fields. This is a slight limitation for users of
https://github.com/pinojs/pino-http[pino-http] which does this.


[float]
[[pino-ref]]
=== Reference

[float]
[[pino-ref-ecsFormat]]
==== `ecsFormat([options])`

* `options` +{type-object}+ The following options are supported:
** `convertErr` +{type-boolean}+ Whether to convert a logged `err` field to ECS error fields. *Default:* `true`.
** `convertReqRes` +{type-boolean}+ Whether to logged `req` and `res` HTTP request and response fields to ECS HTTP, User agent, and URL fields. *Default:* `false`.
** `apmIntegration` +{type-boolean}+ Whether to enable APM agent integration. *Default:* `true`.
** `serviceName` +{type-string}+ A "service.name" value. If specified this overrides any value from an active APM agent.
** `serviceVersion` +{type-string}+ A "service.version" value. If specified this overrides any value from an active APM agent.
** `serviceEnvironment` +{type-string}+ A "service.environment" value. If specified this overrides any value from an active APM agent.
** `serviceNodeName` +{type-string}+ A "service.node.name" value. If specified this overrides any value from an active APM agent.
** `eventDataset` +{type-string}+ A "event.dataset" value. If specified this overrides the default of using `${serviceVersion}`.

Create options for `pino(...)` that configures ECS Logging format output.
45 changes: 37 additions & 8 deletions docs/winston.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const winston = require('winston')
const ecsFormat = require('@elastic/ecs-winston-format')
const logger = winston.createLogger({
format: ecsFormat(), <1>
format: ecsFormat(/* options */), <1>
transports: [
new winston.transports.Console()
]
Expand Down Expand Up @@ -63,7 +63,7 @@ const ecsFormat = require('@elastic/ecs-winston-format')
const logger = winston.createLogger({
level: 'info',
format: ecsFormat(), <1>
format: ecsFormat(/* options */), <1>
transports: [
new winston.transports.Console()
]
Expand All @@ -72,6 +72,7 @@ const logger = winston.createLogger({
logger.info('hi')
logger.error('oops there is a problem', { foo: 'bar' })
----
<1> See available options <<winston-ref,below>>.

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:

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

[float]
[[winston-apm]]
=== Integration with APM Tracing
=== Log Correlation with APM

This ECS log formatter integrates with https://www.elastic.co/apm[Elastic APM].
If your Node app is using the {apm-node-ref}/intro.html[Node.js Elastic APM Agent],
then fields are added to log records that {ecs-ref}/ecs-tracing.html[identify an active trace] and the configured service name
({ecs-ref}/ecs-service.html["service.name"] and {ecs-ref}/ecs-event.html["event.dataset"]).
These fields allow cross linking between traces and logs in Kibana and support
log anomaly detection.
then a number of fields are added to log records to correlate between APM
services or traces and logging data:

- Log statements (e.g. `logger.info(...)`) called when there is a current
tracing span will include {ecs-ref}/ecs-tracing.html[tracing fields] --
`trace.id`, `transaction.id`, `span.id`.
- A number of service identifier fields determined by or configured on the APM
agent allow cross-linking between services and logs in Kibana --
`service.name`, `service.version`, `service.environment`, `service.node.name`.
- `event.dataset` enables {observability-guide}/inspect-log-anomalies.html[log
rate anomaly detection] in the Elastic Observability app.

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:

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

[float]
[[winston-ref]]
=== Reference

[float]
[[winston-ref-ecsFormat]]
==== `ecsFormat([options])`

* `options` +{type-object}+ The following options are supported:
** `convertErr` +{type-boolean}+ Whether to convert a logged `err` field to ECS error fields. *Default:* `true`.
** `convertReqRes` +{type-boolean}+ Whether to logged `req` and `res` HTTP request and response fields to ECS HTTP, User agent, and URL fields. *Default:* `false`.
** `apmIntegration` +{type-boolean}+ Whether to enable APM agent integration. *Default:* `true`.
** `serviceName` +{type-string}+ A "service.name" value. If specified this overrides any value from an active APM agent.
** `serviceVersion` +{type-string}+ A "service.version" value. If specified this overrides any value from an active APM agent.
** `serviceEnvironment` +{type-string}+ A "service.environment" value. If specified this overrides any value from an active APM agent.
** `serviceNodeName` +{type-string}+ A "service.node.name" value. If specified this overrides any value from an active APM agent.
** `eventDataset` +{type-string}+ A "event.dataset" value. If specified this overrides the default of using `${serviceVersion}`.

Create a formatter for winston that emits in ECS Logging format.
10 changes: 10 additions & 0 deletions loggers/morgan/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,22 @@

## Unreleased

- Add `service.version`, `service.environment`, and `service.node.name` log
correlation fields, automatically inferred from an active APM agent. As
well, the following `ecsFormat` configuration options have been added for
overriding these and existing correlation fields: `serviceName`,
`serviceVersion`, `serviceEnvironment`, `serviceNodeName`.
(https://github.com/elastic/apm-agent-nodejs/issues/3195,
https://github.com/elastic/ecs-logging-nodejs/issues/121,
https://github.com/elastic/ecs-logging-nodejs/issues/87)

- Change to adding dotted field names (`"ecs.version": "1.6.0"`), rather than
namespaced fields (`"ecs": {"version": "1.6.0"}`) for most fields. This is
supported by the ecs-logging spec, and arguably preferred in the ECS logging
docs. It is also what the ecs-logging-java libraries do. The resulting output
is slightly shorter, and accidental collisions with user fields is less
likely.

- Stop adding ".log" suffix to `event.dataset` field.
([#95](https://github.com/elastic/ecs-logging-nodejs/issues/95))

Expand Down
21 changes: 13 additions & 8 deletions loggers/morgan/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const app = require('express')()
const morgan = require('morgan')
const ecsFormat = require('@elastic/ecs-morgan-format')

app.use(morgan(ecsFormat()))
app.use(morgan(ecsFormat(/* options */)))

app.get('/', function (req, res) {
res.send('hello, world!')
Expand All @@ -43,18 +43,16 @@ produce log output similar to the following:
```sh
% node examples/express.js | jq . # piping to jq for pretty-printing
{
"@timestamp": "2021-01-16T00:03:23.279Z",
"@timestamp": "2023-10-16T22:00:33.782Z",
"log.level": "info",
"message": "::1 - - [16/Jan/2021:00:03:23 +0000] \"GET / HTTP/1.1\" 200 13 \"-\" \"curl/7.64.1\"",
"ecs": {
"version": "1.6.0"
},
"message": "::ffff:127.0.0.1 - - [16/Oct/2023:22:00:33 +0000] \"GET / HTTP/1.1\" 200 13 \"-\" \"curl/8.1.2\"",
"http": {
"version": "1.1",
"request": {
"method": "GET",
"headers": {
"host": "localhost:3000",
"user-agent": "curl/8.1.2",
"accept": "*/*"
}
},
Expand All @@ -63,6 +61,7 @@ produce log output similar to the following:
"headers": {
"x-powered-by": "Express",
"content-type": "text/html; charset=utf-8",
"content-length": "13",
"etag": "W/\"d-HwnTDHB9U/PRbFMN1z1wps51lqk\""
},
"body": {
Expand All @@ -75,9 +74,15 @@ produce log output similar to the following:
"domain": "localhost",
"full": "http://localhost:3000/"
},
"client": {
"address": "::ffff:127.0.0.1",
"ip": "::ffff:127.0.0.1",
"port": 60455
},
"user_agent": {
"original": "curl/7.64.1"
}
"original": "curl/8.1.2"
},
"ecs.version": "1.6.0"
}
```

Expand Down
Loading

0 comments on commit 2a17af3

Please sign in to comment.