Skip to content

Commit 7bcaf52

Browse files
authored
Adding support for metrics (#422)
* Updating documentation * Resolving comments * Resolving comments * Resolving comments * Resolving comments * Resolving comments * Resolving comments * resolving comments * resolving comments * Resolving comments
1 parent 24ef6ec commit 7bcaf52

File tree

2 files changed

+206
-89
lines changed

2 files changed

+206
-89
lines changed

src/docs/getting-started/js-sdk/metric-manual-instr.mdx

Lines changed: 99 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -35,67 +35,129 @@ In order to trace your application, the following OpenTelemetry packages will be
3535
```bash lineNumbers=true
3636
$ npm install \
3737
@opentelemetry/api \
38-
@opentelemetry/core \
39-
@opentelemetry/exporter-collector \
40-
@opentelemetry/exporter-collector-grpc \
41-
@opentelemetry/exporter-collector-proto \
42-
@opentelemetry/metrics
38+
@opentelemetry/sdk-node \
39+
@opentelemetry/exporter-metrics-otlp-grpc \
40+
@opentelemetry/sdk-metrics \
41+
@opentelemetry/api-metrics
4342
```
4443

4544
## Instrumenting Code
4645
Once OpenTelemetry Dependencies have been imported to application, we can start to instrument code for creating metrics.
4746

4847
1. Initiate OpenTelemetry Metrics exporter to send metrics to ADOT Collector
4948
```javascript lineNumbers=true
50-
const metricExporter = new CollectorMetricExporter({
51-
serviceName: 'aws-otel-js-sample',
52-
logger: new ConsoleLogger(LogLevel.DEBUG),
53-
// port configured in the Collector config, defaults to 4317
54-
url: "localhost:4317"
55-
// credentials only required if tls setup on Collector instance
56-
credentials: grpc.credentials.createSsl(
57-
fs.readFileSync('./ca.crt'),
58-
fs.readFileSync('./client.key'),
59-
fs.readFileSync('./client.crt')
60-
)
49+
const process = require('process');
50+
const opentelemetry = require("@opentelemetry/sdk-node");
51+
const { Resource } = require("@opentelemetry/resources");
52+
const { SemanticResourceAttributes } = require("@opentelemetry/semantic-conventions");
53+
const { PeriodicExportingMetricReader } = require("@opentelemetry/sdk-metrics");
54+
const { OTLPMetricExporter } = require("@opentelemetry/exporter-metrics-otlp-grpc");
55+
56+
const _resource = Resource.default().merge(new Resource({
57+
[SemanticResourceAttributes.SERVICE_NAME]: "js-sample-app",
58+
}));
59+
}
60+
const _metricReader = new PeriodicExportingMetricReader({
61+
exporter: new OTLPMetricExporter(),
62+
exportIntervalMillis: 1000
6163
});
6264
```
6365

6466
2. Create a OpenTelemetry Metric Provider for initiating metrics
6567
```javascript lineNumbers=true
66-
const meter = new MeterProvider({
67-
exporter: metricExporter,
68-
interval: 1000,
69-
}).getMeter('aws-otel-js');
68+
async function nodeSDKBuilder() {
69+
const sdk = new opentelemetry.NodeSDK({
70+
metricReader: _metricReader,
71+
resource: _resource,
72+
});
73+
74+
// this enables the API to record telemetry
75+
await sdk.start();
76+
// gracefully shut down the SDK on process exit
77+
process.on('SIGTERM', () => {
78+
sdk.shutdown()
79+
.then(() => console.log('Metrics terminated'))
80+
.catch((error) => console.log('Error terminating metrics', error))
81+
.finally(() => process.exit(0));
82+
});
83+
}
7084
```
7185

72-
3. Define Metrics and metrics labels(dimensions) for the application
73-
```javascript lineNumbers=true
74-
/** Counter Metrics */
75-
const payloadMetric = meter.createCounter('payload', {
76-
description: 'Metric for counting request payload size',
86+
3. Define metrics and metric labels(dimensions) for the application
87+
In the following example application we demonstrate how to use the three types of metric instruments that
88+
are available to record metrics: Counters, Gauges and Histograms.
89+
90+
[Counters](https://opentelemetry.io/docs/reference/specification/metrics/api/#counter):
91+
```JavaScript
92+
const metricsApi = require('@opentelemetry/api-metrics');
93+
const common_attributes = { signal: 'metric', language: 'javascript', metricType: 'random' };
94+
95+
// acquire meter
96+
const meter = metricsApi.metrics.getMeter('js-sample-app-meter');
97+
98+
// synchronous counter metric
99+
const counterExample = meter.createCounter('counter', {
100+
description: 'Creates a counter metric',
101+
unit: 's'
77102
});
78103

79-
/** Up and Down Counter Metrics */
80-
const activeReqMetric = meter.createUpDownCounter('activeRequest', {
81-
description: 'Metric for record active requests',
104+
// asynchronous updown counter metric
105+
const observableUpdownCounterExample = meter.createObservableUpDownCounter('updownCounter', {
106+
description: 'Creates an asynchronous updown counter metric',
107+
unit:'1'
82108
});
109+
observableUpdownCounterExample.addCallback((measurement) => {measurement.observe(counterVar, common_attributes)});
110+
111+
// updates updown counter
112+
function updateObservableCounter() {
113+
counterVar += Math.random() * 100;
114+
}
115+
```
116+
117+
[Gauges](https://opentelemetry.io/docs/reference/specification/metrics/api/#asynchronous-gauge):
118+
```JavaScript
119+
const metricsApi = require('@opentelemetry/api-metrics');
120+
const common_attributes = { signal: 'metric', language: 'javascript', metricType: 'random' };
121+
122+
// acquire meter
123+
const meter = metricsApi.metrics.getMeter('js-sample-app-meter');
83124

84-
/** Value Recorder Metrics with Histogram */
85-
const requestLatency = meter.createValueRecorder('latency', {
86-
description: 'Metric for record request latency',
125+
// observable gauge metric
126+
const observableGaugeExample = meter.createObservableGauge('observableGauge', {
127+
description: 'Creates an observable gauge metric',
128+
unit: '1'
87129
});
130+
observableGaugeExample.addCallback((measurement) => {measurement.observe(gaugeVar, common_attributes)});
88131

89-
/** Define Metrics Dimensions */
90-
const labels = { pid: process.pid, env: 'beta' };
132+
// updates observable gauge
133+
function updateObservableGauge() {
134+
gaugeVar = Math.random() * 100;
135+
}
136+
```
137+
138+
[Histograms](https://opentelemetry.io/docs/reference/specification/metrics/api/#histogram):
139+
```JavaScript
140+
const metricsApi = require('@opentelemetry/api-metrics');
141+
142+
// acquire meter
143+
const meter = metricsApi.metrics.getMeter('js-sample-app-meter');
144+
145+
const histogramExample = meter.createHistogram('histogram', {
146+
description: "Creates a histogram metric.",
147+
unit: 'ms'
148+
});
91149
```
92150

93151
4. Send metrics
94-
```javascript lineNumbers=true
152+
```JavaScript
153+
const common_attributes = { signal: 'metric', language: 'javascript', metricType: 'random' };
154+
155+
// update metrics
95156
setInterval(() => {
96-
payloadMetric.bind(labels).add(1);
97-
activeReqMetric.bind(labels).add(Math.random() > 0.5 ? 1 : -1);
98-
requestLatency.bind(labels).record(Math.random() * 1000)
157+
counterExample.add(1, common_attributes);
158+
updateObservableCounter();
159+
updateObservableGauge();
160+
histogramExample.record(Math.random() * 1000, common_attributes);
99161
}, 1000);
100162
```
101163

src/docs/getting-started/js-sdk/trace-manual-instr.mdx

Lines changed: 107 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ In order to trace your application, the following OpenTelemetry JavaScript packa
4242
```bash
4343
npm install --save \
4444
@opentelemetry/api \
45-
@opentelemetry/sdk-trace-node \
45+
opentelemetry/sdk-node \
4646
@opentelemetry/exporter-trace-otlp-grpc
4747
```
4848

@@ -62,50 +62,51 @@ npm install --save \
6262

6363
In order to send trace data to AWS X-Ray via the ADOT Collector, you must configure the X-Ray ID generator, X-Ray propagator, and collector gRPC exporter on the global tracer provider.
6464

65-
```javascript lineNumbers=true
66-
const { BatchSpanProcessor } = require("@opentelemetry/sdk-trace-base");
67-
const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node");
68-
const { Resource } = require('@opentelemetry/resources');
69-
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
70-
const { OTLPTraceExporter } = require("@opentelemetry/exporter-trace-otlp-grpc");
65+
```javascript lineNumbers=true
66+
const process = require('process');
67+
const opentelemetry = require("@opentelemetry/sdk-node");
68+
const { Resource } = require("@opentelemetry/resources");
69+
const { SemanticResourceAttributes } = require("@opentelemetry/semantic-conventions");
70+
const { BatchSpanProcessor} = require('@opentelemetry/sdk-trace-base');
71+
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-grpc');
7172
const { AWSXRayPropagator } = require("@opentelemetry/propagator-aws-xray");
7273
const { AWSXRayIdGenerator } = require("@opentelemetry/id-generator-aws-xray");
73-
const { trace } = require("@opentelemetry/api");
74-
75-
module.exports = (serviceName) => {
76-
// create a provider using the AWS ID Generator
77-
const tracerConfig = {
74+
const { HttpInstrumentation } = require("@opentelemetry/instrumentation-http");
75+
const { AwsInstrumentation } = require("opentelemetry-instrumentation-aws-sdk");
76+
77+
const _resource = Resource.default().merge(new Resource({
78+
[SemanticResourceAttributes.SERVICE_NAME]: "js-sample-app",
79+
}));
80+
const _traceExporter = new OTLPTraceExporter();
81+
const _spanProcessor = new BatchSpanProcessor(_traceExporter);
82+
const _tracerConfig = {
7883
idGenerator: new AWSXRayIdGenerator(),
79-
// any instrumentations can be declared here
80-
instrumentations: [],
81-
// any resources can be declared here
82-
resource: Resource.default().merge(new Resource({
83-
[SemanticResourceAttributes.SERVICE_NAME]: serviceName
84-
}))
85-
};
86-
87-
const tracerProvider = new NodeTracerProvider(tracerConfig);
88-
89-
// add OTLP exporter
90-
const otlpExporter = new OTLPTraceExporter({
91-
// port configured in the Collector config, defaults to 4317
92-
url: "localhost:4317"
93-
// credentials only required if mTLS is configured on Collector instance
94-
credentials: grpc.credentials.createSsl(
95-
fs.readFileSync("./ca.crt"),
96-
fs.readFileSync("./client.key"),
97-
fs.readFileSync("./client.crt")
98-
)
99-
});
100-
tracerProvider.addSpanProcessor(new BatchSpanProcessor(otlpExporter));
101-
102-
// Register the tracer provider with an X-Ray propagator
103-
tracerProvider.register({
104-
propagator: new AWSXRayPropagator()
105-
});
106-
107-
// Return an tracer instance
108-
return trace.getTracer("sample-instrumentation");
84+
}
85+
86+
async function nodeSDKBuilder() {
87+
const sdk = new opentelemetry.NodeSDK({
88+
textMapPropagator: new AWSXRayPropagator(),
89+
instrumentations: [
90+
new HttpInstrumentation(),
91+
new AwsInstrumentation({
92+
suppressInternalInstrumentation: true
93+
}),
94+
],
95+
resource: _resource,
96+
spanProcessor: _spanProcessor,
97+
traceExporter: _traceExporter,
98+
});
99+
sdk.configureTracerProvider(_tracerConfig, _spanProcessor);
100+
101+
// this enables the API to record telemetry
102+
await sdk.start();
103+
// gracefully shut down the SDK on process exit
104+
process.on('SIGTERM', () => {
105+
sdk.shutdown()
106+
.then(() => console.log('Tracing and Metrics terminated'))
107+
.catch((error) => console.log('Error terminating tracing and metrics', error))
108+
.finally(() => process.exit(0));
109+
});
109110
}
110111
```
111112

@@ -132,6 +133,53 @@ const tracerProvider = new NodeTracerProvider({ resource });
132133

133134
To see what attributes are captured and how to add other resource detectors, see the [OpenTelemetry documentation](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/detectors/node/opentelemetry-resource-detector-aws#readme).
134135

136+
### Adding support for Metrics
137+
138+
The API and SDK for Metrics became stable for OpenTelemetry for JavaScript.
139+
The following piece of code initialize the OpenTelemetry SDK to use Metrics and Traces.
140+
141+
```JavaScript
142+
const _resource = Resource.default().merge(new Resource({
143+
[SemanticResourceAttributes.SERVICE_NAME]: "js-sample-app",
144+
}));
145+
const _traceExporter = new OTLPTraceExporter();
146+
const _spanProcessor = new BatchSpanProcessor(_traceExporter);
147+
const _tracerConfig = {
148+
idGenerator: new AWSXRayIdGenerator(),
149+
}
150+
const _metricReader = new PeriodicExportingMetricReader({
151+
exporter: new OTLPMetricExporter(),
152+
exportIntervalMillis: 1000
153+
});
154+
155+
async function nodeSDKBuilder() {
156+
const sdk = new opentelemetry.NodeSDK({
157+
textMapPropagator: new AWSXRayPropagator(),
158+
metricReader: _metricReader,
159+
instrumentations: [
160+
new HttpInstrumentation(),
161+
new AwsInstrumentation({
162+
suppressInternalInstrumentation: true
163+
}),
164+
],
165+
resource: _resource,
166+
spanProcessor: _spanProcessor,
167+
traceExporter: _traceExporter,
168+
});
169+
sdk.configureTracerProvider(_tracerConfig, _spanProcessor);
170+
171+
// this enables the API to record telemetry
172+
await sdk.start();
173+
// gracefully shut down the SDK on process exit
174+
process.on('SIGTERM', () => {
175+
sdk.shutdown()
176+
.then(() => console.log('Tracing and Metrics terminated'))
177+
.catch((error) => console.log('Error terminating tracing and metrics', error))
178+
.finally(() => process.exit(0));
179+
});
180+
}
181+
```
182+
135183
### Debug Logging
136184

137185
To enable debug logging for the OpenTelemetry SDK, configure the provided Diag logger as follows. Do this as early in your program as possible to capture all OpenTelemetry SDK behavior.
@@ -166,15 +214,17 @@ Then register the AWS SDK instrumentation as follows:
166214

167215
```js lineNumbers=true
168216
const { AwsInstrumentation } = require('@opentelemetry/instrumentation-aws-sdk');
169-
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
170-
171-
registerInstrumentations({
172-
instrumentations: [
173-
new AwsInstrumentation({
174-
// see the upstream documentation for available configuration
175-
})
176-
]
177-
});
217+
218+
const sdk = new opentelemetry.NodeSDK({
219+
instrumentations: [
220+
new AwsInstrumentation({
221+
suppressInternalInstrumentation: true
222+
}),
223+
],
224+
resource: _resource,
225+
spanProcessor: _spanProcessor,
226+
traceExporter: _traceExporter,
227+
});
178228
```
179229

180230
<SubSectionSeparator />
@@ -208,7 +258,12 @@ const span = tracer.startActiveSpan('sample');
208258
span.setAttribute('key', 'value');
209259
span.end();
210260
```
261+
### Creating Metrics
262+
263+
Similarly to Traces, you can create custom metrics in your application using the OpenTelemetry API and SDK.
264+
Refer to <Link to="/docs/getting-started/js-sdk/metric-manual-instr">Metric-Manual-Instrumentation</Link> for introduction to metric creation using OpenTelemetry JavaScript SDK.
265+
211266

212267
## Sample Application
213268

214-
See the [AWS Distro for OpenTelemetry Sample Code with JavaScript SDK](https://github.com/aws-observability/aws-otel-js/tree/main/sample-apps) for instructions on setting up and using the sample app.
269+
See the [AWS Distro for OpenTelemetry Sample Code with JavaScript SDK](https://github.com/aws-observability/aws-otel-community/tree/master/sample-apps/javascript-sample-app) for instructions on setting up and using the sample app.

0 commit comments

Comments
 (0)