Skip to content

Commit

Permalink
Merge branch 'master' into otel-sampling-probability
Browse files Browse the repository at this point in the history
  • Loading branch information
Naseem committed Jul 8, 2020
2 parents f30a7de + 264fb36 commit 3f3b9a8
Show file tree
Hide file tree
Showing 42 changed files with 1,392 additions and 235 deletions.
1 change: 1 addition & 0 deletions examples/collector-exporter-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
},
"dependencies": {
"@opentelemetry/api": "^0.9.0",
"@opentelemetry/core": "^0.9.0",
"@opentelemetry/exporter-collector": "^0.9.0",
"@opentelemetry/tracing": "^0.9.0"
},
Expand Down
8 changes: 5 additions & 3 deletions examples/collector-exporter-node/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

const opentelemetry = require('@opentelemetry/api');
const { BasicTracerProvider, ConsoleSpanExporter, SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector');
const { CollectorTraceExporter, CollectorProtocolNode } = require('@opentelemetry/exporter-collector');

const address = '127.0.0.1:55680';
const exporter = new CollectorTraceExporter({
serviceName: 'basic-service',
url: address,
// headers: {
// foo: 'bar'
// },
protocolNode: CollectorProtocolNode.HTTP_JSON,
});

const provider = new BasicTracerProvider();
Expand Down
25 changes: 24 additions & 1 deletion packages/opentelemetry-exporter-collector/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ provider.register();

```

## Usage in Node
## Usage 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,6 +109,29 @@ provider.register();

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

## Usage in Node - JSON over http

```js
const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/tracing');
const { CollectorExporter, CollectorTransportNode } = require('@opentelemetry/exporter-collector');

const collectorOptions = {
protocolNode: CollectorTransportNode.HTTP_JSON,
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
};

const provider = new BasicTracerProvider();
const exporter = new CollectorExporter(collectorOptions);
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));

provider.register();

```

## Running opentelemetry-collector locally to see the traces

1. Go to examples/basic-tracer-node
Expand Down
1 change: 1 addition & 0 deletions packages/opentelemetry-exporter-collector/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"@opentelemetry/api": "^0.9.0",
"@opentelemetry/core": "^0.9.0",
"@opentelemetry/resources": "^0.9.0",
"@opentelemetry/metrics": "^0.9.0",
"@opentelemetry/tracing": "^0.9.0",
"google-protobuf": "^3.11.4",
"grpc": "^1.24.2"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* 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 { MetricExporter, MetricRecord } from '@opentelemetry/metrics';
import { Attributes, Logger } from '@opentelemetry/api';
import { CollectorExporterConfigBase } from './types';
import { NoopLogger, ExportResult } from '@opentelemetry/core';
import * as collectorTypes from './types';

const DEFAULT_SERVICE_NAME = 'collector-metric-exporter';

/**
* Collector Metric Exporter abstract base class
*/
export abstract class CollectorMetricExporterBase<
T extends CollectorExporterConfigBase
> implements MetricExporter {
public readonly serviceName: string;
public readonly url: string;
public readonly logger: Logger;
public readonly hostname: string | undefined;
public readonly attributes?: Attributes;
protected readonly _startTime = new Date().getTime() * 1000000;
private _isShutdown: boolean = false;

/**
* @param config
*/
constructor(config: T = {} as T) {
this.logger = config.logger || new NoopLogger();
this.serviceName = config.serviceName || DEFAULT_SERVICE_NAME;
this.url = this.getDefaultUrl(config.url);
this.attributes = config.attributes;
if (typeof config.hostname === 'string') {
this.hostname = config.hostname;
}
this.onInit();
}

/**
* Export metrics
* @param metrics
* @param resultCallback
*/
export(
metrics: MetricRecord[],
resultCallback: (result: ExportResult) => void
) {
if (this._isShutdown) {
resultCallback(ExportResult.FAILED_NOT_RETRYABLE);
return;
}

this._exportMetrics(metrics)
.then(() => {
resultCallback(ExportResult.SUCCESS);
})
.catch((error: collectorTypes.ExportServiceError) => {
if (error.message) {
this.logger.error(error.message);
}
if (error.code && error.code < 500) {
resultCallback(ExportResult.FAILED_NOT_RETRYABLE);
} else {
resultCallback(ExportResult.FAILED_RETRYABLE);
}
});
}

private _exportMetrics(metrics: MetricRecord[]): Promise<unknown> {
return new Promise((resolve, reject) => {
try {
this.logger.debug('metrics to be sent', metrics);
// Send metrics to [opentelemetry collector]{@link https://github.com/open-telemetry/opentelemetry-collector}
// it will use the appropriate transport layer automatically depends on platform
this.sendMetrics(metrics, resolve, reject);
} catch (e) {
reject(e);
}
});
}

/**
* Shutdown the exporter.
*/
shutdown(): void {
if (this._isShutdown) {
this.logger.debug('shutdown already started');
return;
}
this._isShutdown = true;
this.logger.debug('shutdown started');

// platform dependent
this.onShutdown();
}

abstract getDefaultUrl(url: string | undefined): string;
abstract onInit(): void;
abstract onShutdown(): void;
abstract sendMetrics(
metrics: MetricRecord[],
onSuccess: () => void,
onError: (error: collectorTypes.CollectorExporterError) => void
): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ import { Attributes, Logger } from '@opentelemetry/api';
import { ExportResult, NoopLogger } from '@opentelemetry/core';
import { ReadableSpan, SpanExporter } from '@opentelemetry/tracing';
import {
opentelemetryProto,
CollectorExporterError,
CollectorExporterConfigBase,
ExportServiceError,
} from './types';

const DEFAULT_SERVICE_NAME = 'collector-exporter';
Expand All @@ -34,7 +34,7 @@ export abstract class CollectorTraceExporterBase<
public readonly serviceName: string;
public readonly url: string;
public readonly logger: Logger;
public readonly hostName: string | undefined;
public readonly hostname: string | undefined;
public readonly attributes?: Attributes;
private _isShutdown: boolean = false;

Expand All @@ -43,9 +43,9 @@ export abstract class CollectorTraceExporterBase<
*/
constructor(config: T = {} as T) {
this.serviceName = config.serviceName || DEFAULT_SERVICE_NAME;
this.url = this.getDefaultUrl(config.url);
if (typeof config.hostName === 'string') {
this.hostName = config.hostName;
this.url = this.getDefaultUrl(config);
if (typeof config.hostname === 'string') {
this.hostname = config.hostname;
}

this.attributes = config.attributes;
Expand Down Expand Up @@ -76,20 +76,16 @@ export abstract class CollectorTraceExporterBase<
.then(() => {
resultCallback(ExportResult.SUCCESS);
})
.catch(
(
error: opentelemetryProto.collector.trace.v1.ExportTraceServiceError
) => {
if (error.message) {
this.logger.error(error.message);
}
if (error.code && error.code < 500) {
resultCallback(ExportResult.FAILED_NOT_RETRYABLE);
} else {
resultCallback(ExportResult.FAILED_RETRYABLE);
}
.catch((error: ExportServiceError) => {
if (error.message) {
this.logger.error(error.message);
}
);
if (error.code && error.code < 500) {
resultCallback(ExportResult.FAILED_NOT_RETRYABLE);
} else {
resultCallback(ExportResult.FAILED_RETRYABLE);
}
});
}

private _exportSpans(spans: ReadableSpan[]): Promise<unknown> {
Expand Down Expand Up @@ -127,5 +123,5 @@ export abstract class CollectorTraceExporterBase<
onSuccess: () => void,
onError: (error: CollectorExporterError) => void
): void;
abstract getDefaultUrl(url: string | undefined): string;
abstract getDefaultUrl(config: T): string;
}
24 changes: 24 additions & 0 deletions packages/opentelemetry-exporter-collector/src/enums.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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.
*/

/**
* Collector transport protocol node options
* Default is GRPC
*/
export enum CollectorProtocolNode {
GRPC,
HTTP_JSON,
}
1 change: 1 addition & 0 deletions packages/opentelemetry-exporter-collector/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@
*/

export * from './platform';
export * from './enums';
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@
import { CollectorTraceExporterBase } from '../../CollectorTraceExporterBase';
import { ReadableSpan } from '@opentelemetry/tracing';
import { toCollectorExportTraceServiceRequest } from '../../transform';
import { CollectorExporterConfigBrowser } from '../../types';
import { CollectorExporterConfigBrowser } from './types';
import * as collectorTypes from '../../types';
import { parseHeaders } from '../../util';

const DEFAULT_COLLECTOR_URL = 'http://localhost:55680/v1/trace';

Expand All @@ -28,18 +29,19 @@ const DEFAULT_COLLECTOR_URL = 'http://localhost:55680/v1/trace';
export class CollectorTraceExporter extends CollectorTraceExporterBase<
CollectorExporterConfigBrowser
> {
DEFAULT_HEADERS: { [key: string]: string } = {
DEFAULT_HEADERS: Record<string, string> = {
[collectorTypes.OT_REQUEST_HEADER]: '1',
};
private _headers: { [key: string]: string };
private _headers: Record<string, string>;
private _useXHR: boolean = false;

/**
* @param config
*/
constructor(config: CollectorExporterConfigBrowser = {}) {
super(config);
this._headers = config.headers || this.DEFAULT_HEADERS;
this._headers =
parseHeaders(config.headers, this.logger) || this.DEFAULT_HEADERS;
this._useXHR =
!!config.headers || typeof navigator.sendBeacon !== 'function';
}
Expand All @@ -52,8 +54,8 @@ export class CollectorTraceExporter extends CollectorTraceExporterBase<
window.removeEventListener('unload', this.shutdown);
}

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

sendSpans(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,12 @@
* limitations under the License.
*/

import { Aggregator, Point } from '../types';
import { HrTime } from '@opentelemetry/api';
import { hrTime } from '@opentelemetry/core';
import { CollectorExporterConfigBase } from '../../types';

/** Basic aggregator for LastValue which keeps the last recorded value. */
export class LastValueAggregator implements Aggregator {
private _current: number = 0;
private _lastUpdateTime: HrTime = [0, 0];

update(value: number): void {
this._current = value;
this._lastUpdateTime = hrTime();
}

toPoint(): Point {
return {
value: this._current,
timestamp: this._lastUpdateTime,
};
}
/**
* Collector Exporter Config for Web
*/
export interface CollectorExporterConfigBrowser
extends CollectorExporterConfigBase {
headers?: { [key: string]: string };
}
Loading

0 comments on commit 3f3b9a8

Please sign in to comment.