Skip to content

Commit c5d7b40

Browse files
committed
fix the opentelemetry setup
Signed-off-by: Fredrik Adelöw <freben@gmail.com>
1 parent bb5b6ee commit c5d7b40

File tree

15 files changed

+1742
-143
lines changed

15 files changed

+1742
-143
lines changed

.changeset/sharp-glasses-live.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@backstage/cli': patch
3+
---
4+
5+
Allow passing a `--require` argument through to the Node process during `package start`

docs/tutorials/setup-opentelemetry.md

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -6,42 +6,37 @@ description: Tutorial to setup OpenTelemetry metrics and traces exporters in Bac
66

77
Backstage uses [OpenTelemetery](https://opentelemetry.io/) to instrument its components by reporting traces and metrics.
88

9-
This tutorial shows how to setup exporters in your Backstage backend package. For demonstration purposes we will use the simple console exporters.
9+
This tutorial shows how to setup exporters in your Backstage backend package. For demonstration purposes we will use a Prometheus exporter, but you can adjust your solution to use another one that suits your needs; see for example the article on [OTLP exporters](https://opentelemetry.io/docs/instrumentation/js/exporters/).
1010

1111
## Install dependencies
1212

1313
We will use the OpenTelemetry Node SDK and the `auto-instrumentations-node` packages.
1414

15-
Backstage packages, such as the catalog, uses the OpenTelemetry API to send custom traces and metrics.
15+
Backstage packages, such as the catalog, use the OpenTelemetry API to send custom traces and metrics.
1616
The `auto-instrumentations-node` will automatically create spans for code called in libraries like Express.
1717

1818
```bash
19-
yarn --cwd packages/backend add @opentelemetry/sdk-node \
19+
yarn --cwd packages/backend add \
20+
@opentelemetry/sdk-node \
2021
@opentelemetry/auto-instrumentations-node \
21-
@opentelemetry/sdk-metrics \
22-
@opentelemetry/sdk-trace-node
22+
@opentelemetry/exporter-prometheus
2323
```
2424

2525
## Configure
2626

27-
In your `packages/backend` folder, create an `instrumentation.js` file.
27+
In your `packages/backend/src` folder, create an `instrumentation.js` file.
2828

29-
```typescript
29+
```typescript title="in packages/backend/src/instrumentation.js"
3030
const { NodeSDK } = require('@opentelemetry/sdk-node');
31-
const { ConsoleSpanExporter } = require('@opentelemetry/sdk-trace-node');
3231
const {
3332
getNodeAutoInstrumentations,
3433
} = require('@opentelemetry/auto-instrumentations-node');
35-
const {
36-
PeriodicExportingMetricReader,
37-
ConsoleMetricExporter,
38-
} = require('@opentelemetry/sdk-metrics');
34+
const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus');
3935

36+
const prometheus = new PrometheusExporter();
4037
const sdk = new NodeSDK({
41-
traceExporter: new ConsoleSpanExporter(),
42-
metricReader: new PeriodicExportingMetricReader({
43-
exporter: new ConsoleMetricExporter(),
44-
}),
38+
// You can add a traceExporter field here too
39+
metricReader: prometheus,
4540
instrumentations: [getNodeAutoInstrumentations()],
4641
});
4742

@@ -51,43 +46,34 @@ sdk.start();
5146
You probably won't need all of the instrumentation inside `getNodeAutoInstrumentations()` so make sure to
5247
check the [documentation](https://www.npmjs.com/package/@opentelemetry/auto-instrumentations-node) and tweak it properly.
5348

54-
It's important to setup the NodeSDK and the automatic instrumentation **before** importing any library.
55-
56-
This is why we will use the nodejs [`--require`](https://nodejs.org/api/cli.html#-r---require-module)
57-
flag when we start up the application.
49+
## Local Development Setup
5850

59-
In your `Dockerfile` add the `--require` flag which points to the `instrumentation.js` file
60-
61-
```Dockerfile
51+
It's important to setup the NodeSDK and the automatic instrumentation **before**
52+
importing any library. This is why we will use the nodejs
53+
[`--require`](https://nodejs.org/api/cli.html#-r---require-module) flag when we
54+
start up the application.
6255

63-
# We need the instrumentation file inside the Docker image so we can use it with --require
64-
// highlight-add-next-line
65-
COPY --chown=node:node packages/backend/instrumentation.js ./
56+
For local development, you can add the required flag in your `packages/backend/package.json`.
6657

67-
// highlight-remove-next-line
68-
CMD ["node", "packages/backend", "--config", "app-config.yaml"]
69-
// highlight-add-next-line
70-
CMD ["node", "--require", "./instrumentation.js", "packages/backend", "--config", "app-config.yaml"]
58+
```json title="packages/backend/package.json"
59+
"scripts": {
60+
"start": "backstage-cli package start --require ./src/instrumentation.js",
61+
...
7162
```
7263

73-
## Run Backstage
64+
You can now start your Backstage instance as usual, using `yarn dev`.
7465

75-
The above configuration will only work in production once your start a Docker container from the image.
66+
## Production Setup
7667

77-
To be able to test locally you can import the `./instrumentation.js` file at the top (before all imports) of your backend `index.ts` file
68+
In your `Dockerfile` add the `--require` flag which points to the `instrumentation.js` file
7869

79-
```ts
80-
import '../instrumentation.js'
81-
// Other imports
82-
...
70+
```Dockerfile
71+
// highlight-remove-next-line
72+
CMD ["node", "packages/backend", "--config", "app-config.yaml"]
73+
// highlight-add-next-line
74+
CMD ["node", "--require", "./src/instrumentation.js", "packages/backend", "--config", "app-config.yaml"]
8375
```
8476

85-
You can now start your Backstage instance as usual, using `yarn dev`.
86-
87-
When the backend is started, you should see in your console traces and metrics emitted by OpenTelemetry.
88-
89-
Of course in production you probably won't use the console exporters but instead send traces and metrics to an OpenTelemetry Collector or other exporter using [OTLP exporters](https://opentelemetry.io/docs/instrumentation/js/exporters/).
90-
9177
If you need to disable/configure some OpenTelemetry feature there are lots of [environment variables](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/) which you can tweak.
9278

9379
## References

packages/backend-legacy/package.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,6 @@
6565
"@backstage/plugin-techdocs-backend": "workspace:^",
6666
"@gitbeaker/node": "^35.1.0",
6767
"@octokit/rest": "^19.0.3",
68-
"@opentelemetry/api": "^1.4.1",
69-
"@opentelemetry/exporter-prometheus": "^0.50.0",
70-
"@opentelemetry/sdk-metrics": "^1.13.0",
7168
"azure-devops-node-api": "^12.0.0",
7269
"better-sqlite3": "^9.0.0",
7370
"dockerode": "^4.0.0",

packages/backend-legacy/src/index.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -56,19 +56,8 @@ import { ServerPermissionClient } from '@backstage/plugin-permission-node';
5656
import { DefaultIdentityClient } from '@backstage/plugin-auth-node';
5757
import { DefaultEventBroker } from '@backstage/plugin-events-backend';
5858
import { DefaultEventsService } from '@backstage/plugin-events-node';
59-
import { PrometheusExporter } from '@opentelemetry/exporter-prometheus';
60-
import { MeterProvider } from '@opentelemetry/sdk-metrics';
61-
import { metrics } from '@opentelemetry/api';
6259
import { DefaultSignalsService } from '@backstage/plugin-signals-node';
6360

64-
// Expose opentelemetry metrics using a Prometheus exporter on
65-
// http://localhost:9464/metrics . See prometheus.yml in packages/backend for
66-
// more information on how to scrape it.
67-
const exporter = new PrometheusExporter();
68-
const meterProvider = new MeterProvider();
69-
metrics.setGlobalMeterProvider(meterProvider);
70-
meterProvider.addMetricReader(exporter);
71-
7261
function makeCreateEnv(config: Config) {
7362
const root = getRootLogger();
7463
const reader = UrlReaders.default({ logger: root, config });

packages/backend/package.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121
"build": "backstage-cli package build",
2222
"clean": "backstage-cli package clean",
2323
"lint": "backstage-cli package lint",
24-
"start": "backstage-cli package start",
24+
"start": "backstage-cli package start --require ./src/instrumentation.js",
2525
"test": "backstage-cli package test",
26-
"build-image": "docker build ../.. -f Dockerfile --tag example-backend"
26+
"build-image": "docker build ../.. -f Dockerfile --tag example-backend",
27+
"start:prometheus": "docker run --mount type=bind,source=./prometheus.yml,destination=/etc/prometheus/prometheus.yml --publish published=9090,target=9090,protocol=tcp prom/prometheus"
2728
},
2829
"dependencies": {
2930
"@backstage/backend-defaults": "workspace:^",
@@ -56,7 +57,10 @@
5657
"@backstage/plugin-search-backend-module-techdocs": "workspace:^",
5758
"@backstage/plugin-search-backend-node": "workspace:^",
5859
"@backstage/plugin-signals-backend": "workspace:^",
59-
"@backstage/plugin-techdocs-backend": "workspace:^"
60+
"@backstage/plugin-techdocs-backend": "workspace:^",
61+
"@opentelemetry/auto-instrumentations-node": "^0.43.0",
62+
"@opentelemetry/exporter-prometheus": "^0.50.0",
63+
"@opentelemetry/sdk-node": "^0.50.0"
6064
},
6165
"devDependencies": {
6266
"@backstage/cli": "workspace:^"
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2024 The Backstage Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
const { NodeSDK } = require('@opentelemetry/sdk-node');
18+
const {
19+
getNodeAutoInstrumentations,
20+
} = require('@opentelemetry/auto-instrumentations-node');
21+
const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus');
22+
23+
// Expose opentelemetry metrics using a Prometheus exporter on
24+
// http://localhost:9464/metrics. See packages/backend/prometheus.yml for
25+
// more information on how to scrape it.
26+
const prometheus = new PrometheusExporter();
27+
28+
const sdk = new NodeSDK({
29+
// traceExporter: ...,
30+
metricReader: prometheus,
31+
instrumentations: [getNodeAutoInstrumentations()],
32+
});
33+
34+
sdk.start();

packages/cli/cli-report.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,7 @@ Options:
280280
--check
281281
--inspect [host]
282282
--inspect-brk [host]
283+
--require <path>
283284
-h, --help
284285
```
285286

packages/cli/src/commands/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ export function registerScriptCommand(program: Command) {
120120
'--inspect-brk [host]',
121121
'Enable debugger in Node.js environments, breaking before code starts',
122122
)
123+
.option('--require <path>', 'Add a --require argument to the node process')
123124
.action(lazy(() => import('./start').then(m => m.command)));
124125

125126
command

packages/cli/src/commands/start/command.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export async function command(opts: OptionValues): Promise<void> {
2727
checksEnabled: Boolean(opts.check),
2828
inspectEnabled: opts.inspect,
2929
inspectBrkEnabled: opts.inspectBrk,
30+
require: opts.require,
3031
};
3132

3233
switch (role) {

0 commit comments

Comments
 (0)