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

feat: Collector Metric Exporter for the Web #1308

Merged
merged 51 commits into from
Aug 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
7482b43
Merged from upstream
davidwitten Jul 10, 2020
b02949a
Add test
davidwitten Jul 11, 2020
5bd4fef
Basic node
davidwitten Jul 12, 2020
a002c1d
Tests and functions
davidwitten Jul 13, 2020
1d28df4
minor
davidwitten Jul 13, 2020
cf100b3
new line
davidwitten Jul 13, 2020
6a3e948
DefaultURL
davidwitten Jul 13, 2020
4eb3831
Add JSON tests
davidwitten Jul 13, 2020
547e63b
Test rename
davidwitten Jul 13, 2020
b08de2c
Refactor a lot
davidwitten Jul 14, 2020
dffc3dd
Restored those files
davidwitten Jul 14, 2020
9c9abae
Variable anme
davidwitten Jul 14, 2020
589a0e1
Merge remote-tracking branch 'upstream/master' into browser
davidwitten Jul 15, 2020
6c98095
Duplicate test
davidwitten Jul 15, 2020
0ecb031
Fixed strings
davidwitten Jul 15, 2020
629fa50
Changed metrics to functions and added summary
davidwitten Jul 15, 2020
dc1a492
Fixed tests
davidwitten Jul 16, 2020
5e040b1
Merge remote-tracking branch 'upstream/master' into summary
davidwitten Jul 17, 2020
f08faf3
Merge remote-tracking branch 'upstream/master' into node
davidwitten Jul 17, 2020
12d978c
Merge remote-tracking branch 'upstream/master' into browser
davidwitten Jul 17, 2020
a0bb009
Conflicts
davidwitten Jul 17, 2020
40ef4d4
Conflicts
davidwitten Jul 17, 2020
37f154b
Added browser
davidwitten Jul 17, 2020
707427f
Merge remote-tracking branch 'upstream/master' into everything
davidwitten Jul 20, 2020
70e3061
Merge remote-tracking branch 'upstream/master' into browser
davidwitten Jul 20, 2020
87e3900
Hierarchy
davidwitten Jul 20, 2020
f89378b
Lint
davidwitten Jul 20, 2020
7b90b2c
Rename var
davidwitten Jul 20, 2020
07d0b94
Remove reset
davidwitten Jul 21, 2020
fb9b74c
Reset
davidwitten Jul 21, 2020
b6c7b77
Merge remote-tracking branch 'upstream/master' into browser
davidwitten Jul 24, 2020
495f1c6
Merged
davidwitten Jul 27, 2020
b2e40d0
update submodule
davidwitten Jul 27, 2020
13eda4a
Newline
davidwitten Jul 27, 2020
99abf64
Lint
davidwitten Jul 27, 2020
3ae0247
Documentatiom
davidwitten Jul 28, 2020
7ba0b66
Example
davidwitten Jul 29, 2020
9c292d7
fix: verified example
davidwitten Jul 29, 2020
e61e809
merged
davidwitten Jul 29, 2020
765ddfa
Newline
davidwitten Jul 29, 2020
10236ee
feat: simplified example
davidwitten Jul 29, 2020
44eab55
chore: merge
davidwitten Jul 29, 2020
21c9e8b
chore: rename start
davidwitten Jul 31, 2020
a8857d3
refactor: split up files
davidwitten Jul 31, 2020
15de18b
fix: lint
davidwitten Jul 31, 2020
175e050
fix: add comments
davidwitten Jul 31, 2020
e526e11
fix: private
davidwitten Aug 3, 2020
6d3a080
Merge branch 'master' into browser
dyladan Aug 4, 2020
d29be93
Merge remote-tracking branch 'upstream/master' into browser
davidwitten Aug 4, 2020
ccedacc
fix: readme
davidwitten Aug 4, 2020
775d2a4
Merged
davidwitten Aug 4, 2020
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
22 changes: 19 additions & 3 deletions examples/collector-exporter-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,32 @@ npm install
npm run docker:start
```

2. Run app
2. Run tracing app

```shell script
# from this directory
npm start
npm start:tracing
```

3. Open page at <http://localhost:9411/zipkin/> - you should be able to see the spans in zipkin
3. Run metrics app

```shell script
# from this directory
npm start:metrics
```

4. Open page at <http://localhost:9411/zipkin/> - you should be able to see the spans in zipkin
![Screenshot of the running example](images/spans.png)

### Prometheus UI

The prometheus client will be available at <http://localhost:9090>.

Note: It may take some time for the application metrics to appear on the Prometheus dashboard.

<p align="center"><img src="../prometheus/images/prom-counter.png?raw=true"/></p>
<p align="center"><img src="../prometheus/images/prom-updowncounter.png?raw=true"/></p>

## Useful links

- For more information on OpenTelemetry, visit: <https://opentelemetry.io/>
Expand Down
6 changes: 6 additions & 0 deletions examples/collector-exporter-node/docker/collector-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ receivers:
exporters:
zipkin:
endpoint: "http://zipkin-all-in-one:9411/api/v2/spans"
prometheus:
endpoint: "0.0.0.0:9464"

processors:
batch:
Expand All @@ -21,3 +23,7 @@ service:
receivers: [otlp]
exporters: [zipkin]
processors: [batch, queued_retry]
metrics:
receivers: [otlp]
exporters: [prometheus]
processors: [batch, queued_retry]
15 changes: 9 additions & 6 deletions examples/collector-exporter-node/docker/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ services:
image: otel/opentelemetry-collector:latest
# image: otel/opentelemetry-collector:0.6.0
command: ["--config=/conf/collector-config.yaml", "--log-level=DEBUG"]
networks:
davidwitten marked this conversation as resolved.
Show resolved Hide resolved
- otelcol
volumes:
- ./collector-config.yaml:/conf/collector-config.yaml
ports:
- "9464:9464"
- "55680:55680"
- "55681:55681"
depends_on:
Expand All @@ -18,10 +17,14 @@ services:
# Zipkin
zipkin-all-in-one:
image: openzipkin/zipkin:latest
networks:
- otelcol
ports:
- "9411:9411"

networks:
otelcol:
# Prometheus
prometheus:
container_name: prometheus
image: prom/prometheus:latest
volumes:
- ./prometheus.yaml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
9 changes: 9 additions & 0 deletions examples/collector-exporter-node/docker/prometheus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
global:
scrape_interval: 15s # Default is every 1 minute.

scrape_configs:
- job_name: 'collector'
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ['collector:9464']
29 changes: 29 additions & 0 deletions examples/collector-exporter-node/metrics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector');
const { MeterProvider } = require('@opentelemetry/metrics');

const metricExporter = new CollectorMetricExporter({
serviceName: 'basic-metric-service',
// logger: new ConsoleLogger(LogLevel.DEBUG),
});

const meter = new MeterProvider({
exporter: metricExporter,
interval: 1000,
}).getMeter('example-prometheus');

const requestCounter = meter.createCounter('requests', {
description: 'Example of a Counter',
});

const upDownCounter = meter.createUpDownCounter('test_up_down_counter', {
description: 'Example of a UpDownCounter',
});

const labels = { pid: process.pid, environment: 'staging' };

setInterval(() => {
requestCounter.bind(labels).add(1);
upDownCounter.bind(labels).add(Math.random() > 0.5 ? 1 : -1);
}, 1000);
4 changes: 3 additions & 1 deletion examples/collector-exporter-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"description": "Example of using @opentelemetry/collector-exporter in Node.js",
"main": "index.js",
"scripts": {
"start": "node ./start.js",
"start:tracing": "node tracing.js",
"start:metrics": "node metrics.js",
"docker:start": "cd ./docker && docker-compose down && docker-compose up",
"docker:startd": "cd ./docker && docker-compose down && docker-compose up -d",
"docker:stop": "cd ./docker && docker-compose down"
Expand All @@ -30,6 +31,7 @@
"@opentelemetry/api": "^0.10.2",
"@opentelemetry/core": "^0.10.2",
"@opentelemetry/exporter-collector": "^0.10.2",
"@opentelemetry/metrics": "^0.10.2",
"@opentelemetry/tracing": "^0.10.2"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js#readme"
Expand Down
61 changes: 44 additions & 17 deletions packages/opentelemetry-exporter-collector/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This module provides exporter for web and node to be used with [opentelemetry-co
npm install --save @opentelemetry/exporter-collector
```

## Usage in Web
## Traces in Web

The CollectorTraceExporter in Web expects the endpoint to end in `/v1/trace`.

Expand All @@ -36,7 +36,32 @@ provider.register();

```

## Usage in Node - GRPC
## Metrics in Web

The CollectorMetricExporter in Web expects the endpoint to end in `/v1/metrics`.

```js
import { MetricProvider } from '@opentelemetry/metrics';
import { CollectorMetricExporter } from '@opentelemetry/exporter-collector';
const collectorOptions = {
url: '<opentelemetry-collector-url>', // url is optional and can be omitted - default is http://localhost:55681/v1/metrics
headers: {}, //an optional object containing custom headers to be sent with each request
};
const exporter = new CollectorMetricExporter(collectorOptions);

// Register the exporter
const meter = new MeterProvider({
exporter,
interval: 60000,
}).getMeter('example-meter');

// Now, start recording data
const counter = meter.createCounter('metric_name');
counter.add(10, { 'key': 'value' });

```

## Traces in Node - GRPC

The CollectorTraceExporter in Node expects the URL to only be the hostname. It will not work with `/v1/trace`.

Expand Down Expand Up @@ -109,7 +134,7 @@ provider.register();

Note, that this will only work if TLS is also configured on the server.

## Usage in Node - JSON over http
## Traces in Node - JSON over http

```js
const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/tracing');
Expand All @@ -132,7 +157,7 @@ provider.register();

```

## Usage in Node - PROTO over http
## Traces in Node - PROTO over http

```js
const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/tracing');
Expand All @@ -155,26 +180,28 @@ provider.register();

```

## Usage in Node - PROTO over http
## Metrics in Node

```js
const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { CollectorExporter, CollectorTransportNode } = require('@opentelemetry/exporter-collector');
The CollectorTraceExporter in Node expects the URL to only be the hostname. It will not work with `/v1/metrics`. All options that work with trace also work with metrics.

```js
const { MeterProvider } = require('@opentelemetry/metrics');
const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector');
const collectorOptions = {
protocolNode: CollectorTransportNode.HTTP_PROTO,
serviceName: 'basic-service',
url: '<opentelemetry-collector-url>', // url is optional and can be omitted - default is http://localhost:55680/v1/trace
headers: {
foo: 'bar'
}, //an optional object containing custom headers to be sent with each request will only work with json over http
url: '<opentelemetry-collector-url>', // url is optional and can be omitted - default is localhost:55681
};
const exporter = new CollectorMetricExporter(collectorOptions);

const provider = new BasicTracerProvider();
const exporter = new CollectorExporter(collectorOptions);
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
// Register the exporter
const meter = new MeterProvider({
exporter,
interval: 60000,
}).getMeter('example-meter');

provider.register();
// Now, start recording data
const counter = meter.createCounter('metric_name');
counter.add(10, { 'key': 'value' });

```

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { CollectorExporterBase } from '../../CollectorExporterBase';
import { CollectorExporterConfigBrowser } from './types';
import * as collectorTypes from '../../types';
import { parseHeaders } from '../../util';
import { sendWithBeacon, sendWithXhr } from './util';

/**
* Collector Metric Exporter abstract base class
*/
export abstract class CollectorExporterBrowserBase<
ExportItem,
ServiceRequest
> extends CollectorExporterBase<
CollectorExporterConfigBrowser,
ExportItem,
ServiceRequest
> {
private _headers: Record<string, string>;
private _useXHR: boolean = false;

/**
* @param config
*/
constructor(config: CollectorExporterConfigBrowser = {}) {
super(config);
this._useXHR =
davidwitten marked this conversation as resolved.
Show resolved Hide resolved
!!config.headers || typeof navigator.sendBeacon !== 'function';
if (this._useXHR) {
this._headers = parseHeaders(config.headers, this.logger);
} else {
this._headers = {};
}
}

onInit(): void {
window.addEventListener('unload', this.shutdown);
}

onShutdown(): void {
window.removeEventListener('unload', this.shutdown);
}

send(
items: ExportItem[],
onSuccess: () => void,
onError: (error: collectorTypes.CollectorExporterError) => void
) {
const serviceRequest = this.convert(items);
const body = JSON.stringify(serviceRequest);

if (this._useXHR) {
sendWithXhr(
body,
this.url,
this._headers,
this.logger,
onSuccess,
onError
);
} else {
sendWithBeacon(body, this.url, this.logger, onSuccess, onError);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright The OpenTelemetry Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { MetricRecord, MetricExporter } from '@opentelemetry/metrics';
import * as collectorTypes from '../../types';
import { CollectorExporterBrowserBase } from './CollectorExporterBrowserBase';
import { toCollectorExportMetricServiceRequest } from '../../transformMetrics';
import { CollectorExporterConfigBrowser } from './types';

const DEFAULT_COLLECTOR_URL = 'http://localhost:55680/v1/metrics';
const DEFAULT_SERVICE_NAME = 'collector-metric-exporter';

/**
* Collector Metric Exporter for Web
*/
export class CollectorMetricExporter
extends CollectorExporterBrowserBase<
MetricRecord,
collectorTypes.opentelemetryProto.collector.metrics.v1.ExportMetricsServiceRequest
>
implements MetricExporter {
// Converts time to nanoseconds
private readonly _startTime = new Date().getTime() * 1000000;
davidwitten marked this conversation as resolved.
Show resolved Hide resolved

convert(
metrics: MetricRecord[]
): collectorTypes.opentelemetryProto.collector.metrics.v1.ExportMetricsServiceRequest {
return toCollectorExportMetricServiceRequest(
metrics,
this._startTime,
this
);
}

getDefaultUrl(config: CollectorExporterConfigBrowser): string {
return config.url || DEFAULT_COLLECTOR_URL;
}

getDefaultServiceName(config: CollectorExporterConfigBrowser): string {
return config.serviceName || DEFAULT_SERVICE_NAME;
}
}
Loading