Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add migration guide #368

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 232 additions & 0 deletions packages/opentelemetry-node/docs/migration-from-apm-agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
<!--
Goal of this doc:
Provide a reference of how to switch from `elastic-apm-node`, the classic agent, to `@elastic/opentelemetry-node`. It also
provide guide on passing their ELASTIC_* instrumentation config to EDOT

Assumptions we're comfortable making about the reader:
* They are just starting the agent in any form (REVIEW)
* They are not using any apm, transaction or span APIs (REVIEW)

-->

# Migration from Elastic APM Node.js Agent

This guide shows you how to _migrate_ a service instrumented with Elastic APM Node.js Agent
(classic Agent) with a basic setup to Elastic Distribution of OpenTelemetry Node.js (EDOT Node.js). If your
application is not instrumented with the classic agent please visit
our [get started](./get-started.md) guide in this documentation.


<!-- ✅ What the user needs to know and/or do before they migrate EDOT Node.js -->
## Prerequisites

Before getting started, you'll need to save a minimal set of configuration options from the classic Agent, so
EDOT Node.js can send data to the same deployment of [Elastic Observability](https://www.elastic.co/observability) using the same service name.

The mininmal set of options required for the migration are:

- [server url](https://www.elastic.co/guide/en/apm/agent/nodejs/4.x/configuration.html#server-url)
- [api key](https://www.elastic.co/guide/en/apm/agent/nodejs/4.x/configuration.html#api-key) or [secret token](https://www.elastic.co/guide/en/apm/agent/nodejs/4.x/configuration.html#secret-token)
- [service name](https://www.elastic.co/guide/en/apm/agent/nodejs/4.x/configuration.html#service-name) (optional)



<!-- ✅ Step-by-step instructions of the most common scenario -->
## Migration process

If the service being instrumented is not using any advanced feature like [Agent's APIs](https://www.elastic.co/guide/en/apm/agent/nodejs/4.x/api.html) the
migration process is straight-forward. This section will focus on this scenario and instructions for advanced usage
will be given in futeher sections.

### Uninstall Elastic APM Node.js Agent

Uninstall the `elastic-apm-node` package:

```sh
npm uninstall --save elastic-apm-node
```

Once the pacakge is removed you should proceed to remove any setup made to start the classic agent along with your service.

- remove Node.js `--require` CLI option `NODE_OPTIONS` or the start command if your service is using [Node.js CLI option](https://www.elastic.co/guide/en/apm/agent/nodejs/4.x/starting-the-agent.html#start-option-node-require-opt) start method.
- remove start snippet if your service is starting the agent with one of this options
* [require('elastic-apm-node').start(...)](https://www.elastic.co/guide/en/apm/agent/nodejs/4.x/starting-the-agent.html#start-option-require-and-start)
* [require('elastic-apm-node/start')](https://www.elastic.co/guide/en/apm/agent/nodejs/4.x/starting-the-agent.html#start-option-require-start-module)
- remove the APM module if your service is using [separate APM init module](https://www.elastic.co/guide/en/apm/agent/nodejs/4.x/starting-the-agent.html#start-option-separate-init-module)

### 2. Install EDOT Node.js

Install the `@elastic/opentelemetry-node` package:

```sh
npm install --save @elastic/opentelemetry-node
```

Like Elastic APM Node.js Agent EDOT Node.js is a single package that includes all the
OpenTelemetry JS packages that are needed for most cases.

Once you have the package installed is time to setup the start proces. The recommended way
of starting EDOT Node.js along your application is via `--require` CLI option.

```sh
node --require @elastic/opentelemetry-node my-service.js
```

<!-- ✅ How to change the basic configuration -->
## Configuration of EDOT Node.js

Once you're done with the changes described in the section above it is time to migrate the configuration. EDOT Node.js is
typically configured with `OTEL_*` environment variables defined by the OpenTelemetry spec. Environment variables
are read at startup and can be used to configure EDOT Node.js.

For the minimal configuration mentioned in [prerequisites](#prerequisites) section there are `OTEL_*` variables
from OpenTelemetry spec that fit.

- `OTEL_EXPORTER_OTLP_ENDPOINT` will hold the value of `server_url` configuration option
- `OTEL_EXPORTER_OTLP_HEADERS` will hold the value of `api_key` or `secret_token`
* the value should be `Authorization=Bearer {secret_token}` if `secret_token` was used
* the value should be `Authorization=ApiKEy {api_key}` if `api_key` was used

If you want more information about configuration you may visit [configuration options](./configure.md) page.



## Advanced

There might be some cases where the instrumentation

### Using classic Agent's APIs

If you are doing manual instrumentation of some modules of your service through the [classic Agent's API](https://www.elastic.co/guide/en/apm/agent/nodejs/4.x/api.html)
you will need to refactor it to use `@opentelemetry/api` methods.

Either if you're using `apm.startTransaction` or `apm.startSpan` APIs both could be refactor to the same instrumentation
code using `@opentelemetry/api`. The anatomy of a manual instrumentation using the classig Agent consists in
using `apm.startTransaction` or `apm.startSpan` to mark the beginning of a transaction/span and mark the end
by calling the `.end` API of the transaction or spans returned before.

Example:
```js
// file: my-service.js
//
// NOTE: we're assuming this app is started using Node.js --require CLI option
// node --require elastic-apm-agent my-service.js
const http = require('http');
const apm = require('elastic-apm-agent');

const server = http.createServer(function onRequest(req, res) {
// Start of manual instrumentation
const span = apm.startSpan('Custom Span')

console.log('incoming request: %s %s %s', req.method, req.url, req.headers);
req.resume();
req.on('end', function () {
const body = 'pong';
res.writeHead(200, {
'content-type': 'text/plain',
'content-length': Buffer.byteLength(body),
});
res.end(body);
// Instrumentation end
span.end();
});
});

server.listen(3000, '127.0.0.1', function () {
console.log('listening at', server.address());
});
```

To migrate this code to use `@opentelemetry/api` instead you should:

- remove the require call of `elastic-apm-node`
- require `@opentelemetry/api` and get a tracer
- replace usage of the classic Agent's API with call to the tracer API

```js
// file: my-service.js
//
// NOTE: we're assuming this app is started using Node.js --require CLI option
// node --require @elastic/otel-node my-service.js

const http = require('http');
// Require OTEL API
const api = require('@opentelemetry/api');
// Get a tracer for our manual instrumentation
const tracer = api.tracer.getTracer();

const server = http.createServer(function onRequest(req, res) {
// Start of manual instrumentation. In OTEL is always starting an Span
tracer.startActiveSpan('Custom Span', function (span) { // <-- the measured logic should be wrapped in this callback
console.log('incoming request: %s %s %s', req.method, req.url, req.headers);
req.resume();
req.on('end', function () {
const body = 'pong';
res.writeHead(200, {
'content-type': 'text/plain',
'content-length': Buffer.byteLength(body),
});
res.end(body);
// Instrumentation end
span.end();
});
});
});

server.listen(3000, '127.0.0.1', function () {
console.log('listening at', server.address());
});
```


### Extensive use of config options

TODO: finish review of options
TODO: put this subsection 1st

<!-- ✅ Refernece fo all configurations they can migrate -->

There are other configuration options that can be migrated from `elastic-apm-node` to EDOT Node.js. ...

#### Log Level

The [logLevel](https://www.elastic.co/guide/en/apm/agent/nodejs/current/configuration.html#log-level) option has a direct migration to
OTEL configuration via `OTEL_LOG_LEVEL` environment variable. The possible values change a bit but they represent similar levels. The following
table shows the equivalent values of log levels between `elastic-apm-node` and EDOT Node.js

| ELASTIC_APM_LOG_LEVEL | OTEL_LOG_LEVEL |
| --------------------- | -------------- |
| `off` | `none` |
| `error` | `error` |
| `warn` | `warn` |
| `info` | `info` |
| `debug` | `debug` |
| `trace` | `verbose` |
| `trace` | `all` |

#### Active

The [active](https://www.elastic.co/guide/en/apm/agent/nodejs/current/configuration.html#active) config option has the equivalent in OTEL via the environment variable named `OTEL_SDK_DISABLED`. Notice this it has the opposite meanig so to to disable the agent you shouls set
this condfiguration to the string "true". Any other value will be considered false.


#### Disable instrumentations

There is a couple of ways to migrate [disableInstrumentations](https://www.elastic.co/guide/en/apm/agent/nodejs/current/configuration.html#disable-instrumentations) since the [specification](https://opentelemetry.io/docs/zero-code/js/configuration/) for Node.js defines two environment variables:

- `OTEL_NODE_ENABLED_INSTRUMENTATIONS`: instrumentations listed in this var will be enabled
- `OTEL_NODE_DISABLED_INSTRUMENTATIONS`: instrumentations listed in this var will be disaabled

The quickest way to migrate `disableInstrumentations` is to migrate the list to `OTEL_NODE_DISABLED_INSTRUMENTATIONS` variable. You can check which instrumentations are included in EDOT Node.js in [supported technologies](./supported-technologies.md).


TODO: environment could be set as a resource attrib using `OTEL_RESOURCE_ATTRIBUTES`???


## FAQ

- Will I get the same traces and metrics once the servie is migrated to EDOT Node.js?

TODO: point to supported technologies and metrics documents

- ????
Loading