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(exporter-collector): support config from env #2099 #2117

Merged
merged 9 commits into from
May 12, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ exporters:

processors:
batch:
queued_retry:

service:
pipelines:
traces:
receivers: [otlp]
exporters: [zipkin]
processors: [batch, queued_retry]
processors: [batch]
metrics:
receivers: [otlp]
exporters: [prometheus]
processors: [batch, queued_retry]
processors: [batch]
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: "3"
services:
# Collector
collector:
image: otel/opentelemetry-collector:0.16.0
image: otel/opentelemetry-collector:0.25.0
# image: otel/opentelemetry-collector:latest
command: ["--config=/conf/collector-config.yaml", "--log-level=DEBUG"]
volumes:
Expand Down
28 changes: 28 additions & 0 deletions packages/opentelemetry-core/src/baggage/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.
*/

export const BAGGAGE_KEY_PAIR_SEPARATOR = '=';
export const BAGGAGE_PROPERTIES_SEPARATOR = ';';
export const BAGGAGE_ITEMS_SEPARATOR = ',';

// Name of the http header used to propagate the baggage
export const BAGGAGE_HEADER = 'baggage';
dyladan marked this conversation as resolved.
Show resolved Hide resolved
// Maximum number of name-value pairs allowed by w3c spec
export const BAGGAGE_MAX_NAME_VALUE_PAIRS = 180;
// Maximum number of bytes per a single name-value pair allowed by w3c spec
export const BAGGAGE_MAX_PER_NAME_VALUE_PAIRS = 4096;
// Maximum total length of all name-value pairs allowed by w3c spec
export const BAGGAGE_MAX_TOTAL_LENGTH = 8192;
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/

import {
Baggage,
Context,
BaggageEntry,
getBaggage,
Expand All @@ -24,22 +23,15 @@ import {
TextMapPropagator,
TextMapSetter,
createBaggage,
baggageEntryMetadataFromString,
isInstrumentationSuppressed,
} from '@opentelemetry/api';

const KEY_PAIR_SEPARATOR = '=';
const PROPERTIES_SEPARATOR = ';';
const ITEMS_SEPARATOR = ',';

// Name of the http header used to propagate the baggage
export const BAGGAGE_HEADER = 'baggage';
// Maximum number of name-value pairs allowed by w3c spec
export const MAX_NAME_VALUE_PAIRS = 180;
// Maximum number of bytes per a single name-value pair allowed by w3c spec
export const MAX_PER_NAME_VALUE_PAIRS = 4096;
// Maximum total length of all name-value pairs allowed by w3c spec
export const MAX_TOTAL_LENGTH = 8192;
import { getKeyPairs, serializeKeyPairs, parsePairKeyValue } from '../utils';
import {
BAGGAGE_MAX_NAME_VALUE_PAIRS,
BAGGAGE_ITEMS_SEPARATOR,
BAGGAGE_HEADER,
BAGGAGE_MAX_PER_NAME_VALUE_PAIRS,
} from '../constants';

/**
* Propagates {@link Baggage} through Context format propagation.
Expand All @@ -51,45 +43,27 @@ export class HttpBaggagePropagator implements TextMapPropagator {
inject(context: Context, carrier: unknown, setter: TextMapSetter) {
const baggage = getBaggage(context);
if (!baggage || isInstrumentationSuppressed(context)) return;
const keyPairs = this._getKeyPairs(baggage)
const keyPairs = getKeyPairs(baggage)
.filter((pair: string) => {
return pair.length <= MAX_PER_NAME_VALUE_PAIRS;
return pair.length <= BAGGAGE_MAX_PER_NAME_VALUE_PAIRS;
})
.slice(0, MAX_NAME_VALUE_PAIRS);
const headerValue = this._serializeKeyPairs(keyPairs);
.slice(0, BAGGAGE_MAX_NAME_VALUE_PAIRS);
const headerValue = serializeKeyPairs(keyPairs);
if (headerValue.length > 0) {
setter.set(carrier, BAGGAGE_HEADER, headerValue);
}
}

private _serializeKeyPairs(keyPairs: string[]) {
return keyPairs.reduce((hValue: string, current: string) => {
const value = `${hValue}${
hValue !== '' ? ITEMS_SEPARATOR : ''
}${current}`;
return value.length > MAX_TOTAL_LENGTH ? hValue : value;
}, '');
}

private _getKeyPairs(baggage: Baggage): string[] {
return baggage
.getAllEntries()
.map(
([key, value]) =>
`${encodeURIComponent(key)}=${encodeURIComponent(value.value)}`
);
}

extract(context: Context, carrier: unknown, getter: TextMapGetter): Context {
const headerValue: string = getter.get(carrier, BAGGAGE_HEADER) as string;
if (!headerValue) return context;
const baggage: Record<string, BaggageEntry> = {};
if (headerValue.length === 0) {
return context;
}
const pairs = headerValue.split(ITEMS_SEPARATOR);
const pairs = headerValue.split(BAGGAGE_ITEMS_SEPARATOR);
pairs.forEach(entry => {
const keyPair = this._parsePairKeyValue(entry);
const keyPair = parsePairKeyValue(entry);
if (keyPair) {
const baggageEntry: BaggageEntry = { value: keyPair.value };
if (keyPair.metadata) {
Expand All @@ -104,24 +78,6 @@ export class HttpBaggagePropagator implements TextMapPropagator {
return setBaggage(context, createBaggage(baggage));
}

private _parsePairKeyValue(entry: string) {
const valueProps = entry.split(PROPERTIES_SEPARATOR);
if (valueProps.length <= 0) return;
const keyPairPart = valueProps.shift();
if (!keyPairPart) return;
const keyPair = keyPairPart.split(KEY_PAIR_SEPARATOR);
if (keyPair.length !== 2) return;
const key = decodeURIComponent(keyPair[0].trim());
const value = decodeURIComponent(keyPair[1].trim());
let metadata;
if (valueProps.length > 0) {
metadata = baggageEntryMetadataFromString(
valueProps.join(PROPERTIES_SEPARATOR)
);
}
return { key, value, metadata };
}

fields(): string[] {
return [BAGGAGE_HEADER];
}
Expand Down
76 changes: 76 additions & 0 deletions packages/opentelemetry-core/src/baggage/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* 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 { Baggage, baggageEntryMetadataFromString } from '@opentelemetry/api';
import {
BAGGAGE_ITEMS_SEPARATOR,
BAGGAGE_PROPERTIES_SEPARATOR,
BAGGAGE_KEY_PAIR_SEPARATOR,
BAGGAGE_MAX_TOTAL_LENGTH,
} from './constants';

export const serializeKeyPairs = (keyPairs: string[]) => {
return keyPairs.reduce((hValue: string, current: string) => {
const value = `${hValue}${
hValue !== '' ? BAGGAGE_ITEMS_SEPARATOR : ''
}${current}`;
return value.length > BAGGAGE_MAX_TOTAL_LENGTH ? hValue : value;
}, '');
};

export const getKeyPairs = (baggage: Baggage): string[] => {
return baggage
.getAllEntries()
.map(
([key, value]) =>
`${encodeURIComponent(key)}=${encodeURIComponent(value.value)}`
);
};

export const parsePairKeyValue = (entry: string) => {
const valueProps = entry.split(BAGGAGE_PROPERTIES_SEPARATOR);
if (valueProps.length <= 0) return;
const keyPairPart = valueProps.shift();
if (!keyPairPart) return;
const keyPair = keyPairPart.split(BAGGAGE_KEY_PAIR_SEPARATOR);
if (keyPair.length !== 2) return;
const key = decodeURIComponent(keyPair[0].trim());
const value = decodeURIComponent(keyPair[1].trim());
let metadata;
if (valueProps.length > 0) {
metadata = baggageEntryMetadataFromString(
valueProps.join(BAGGAGE_PROPERTIES_SEPARATOR)
);
}
return { key, value, metadata };
};

/**
* Parse a string serialized in the baggage HTTP Format (without metadata):
* https://github.com/w3c/baggage/blob/master/baggage/HTTP_HEADER_FORMAT.md
*/
export const parseKeyPairsIntoRecord = (value?: string) => {
if (typeof value !== 'string' || value.length === 0) return {};
return value
.split(BAGGAGE_ITEMS_SEPARATOR)
.map(entry => {
return parsePairKeyValue(entry);
})
.filter(keyPair => keyPair !== undefined && keyPair.value.length > 0)
.reduce<Record<string, string>>((headers, keyPair) => {
headers[keyPair!.key] = keyPair!.value;
return headers;
}, {});
};
2 changes: 2 additions & 0 deletions packages/opentelemetry-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export * from './common/logging-error-handler';
export * from './common/time';
export * from './common/types';
export * from './ExportResult';
export * from './version';
export * as baggageUtils from './baggage/utils';
export * from './platform';
export * from './propagation/composite';
export * from './trace/HttpTraceContextPropagator';
Expand Down
12 changes: 12 additions & 0 deletions packages/opentelemetry-core/src/utils/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,12 @@ export type ENVIRONMENT = {
OTEL_EXPORTER_JAEGER_ENDPOINT?: string;
OTEL_EXPORTER_JAEGER_PASSWORD?: string;
OTEL_EXPORTER_JAEGER_USER?: string;
OTEL_EXPORTER_OTLP_ENDPOINT?: string;
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT?: string;
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT?: string;
OTEL_EXPORTER_OTLP_HEADERS?: string;
OTEL_EXPORTER_OTLP_TRACES_HEADERS?: string;
OTEL_EXPORTER_OTLP_METRICS_HEADERS?: string;
OTEL_EXPORTER_ZIPKIN_ENDPOINT?: string;
OTEL_LOG_LEVEL?: DiagLogLevel;
OTEL_RESOURCE_ATTRIBUTES?: string;
Expand Down Expand Up @@ -97,6 +103,12 @@ export const DEFAULT_ENVIRONMENT: Required<ENVIRONMENT> = {
OTEL_EXPORTER_JAEGER_ENDPOINT: '',
OTEL_EXPORTER_JAEGER_PASSWORD: '',
OTEL_EXPORTER_JAEGER_USER: '',
OTEL_EXPORTER_OTLP_ENDPOINT: '',
OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '',
OTEL_EXPORTER_OTLP_METRICS_ENDPOINT: '',
OTEL_EXPORTER_OTLP_HEADERS: '',
OTEL_EXPORTER_OTLP_TRACES_HEADERS: '',
OTEL_EXPORTER_OTLP_METRICS_HEADERS: '',
OTEL_EXPORTER_ZIPKIN_ENDPOINT: 'http://localhost:9411/api/v2/spans',
OTEL_LOG_LEVEL: DiagLogLevel.INFO,
OTEL_NO_PATCH_MODULES: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@ import {
} from '@opentelemetry/api';
import { ROOT_CONTEXT } from '@opentelemetry/api';
import * as assert from 'assert';
import {
BAGGAGE_HEADER,
HttpBaggagePropagator,
} from '../../src/baggage/propagation/HttpBaggagePropagator';
import { HttpBaggagePropagator } from '../../src/baggage/propagation/HttpBaggagePropagator';
import { BAGGAGE_HEADER } from '../../src/baggage/constants';

describe('HttpBaggagePropagator', () => {
const httpBaggagePropagator = new HttpBaggagePropagator();
Expand Down
4 changes: 2 additions & 2 deletions packages/opentelemetry-exporter-collector-grpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![devDependencies][devDependencies-image]][devDependencies-url]
[![Apache License][license-image]][license-image]

This module provides exporter for web and node to be used with [opentelemetry-collector][opentelemetry-collector-url] - last tested with version **0.16.0**.
This module provides exporter for web and node to be used with [opentelemetry-collector][opentelemetry-collector-url] - last tested with version **0.25.0**.

## Installation

Expand All @@ -15,7 +15,7 @@ npm install --save @opentelemetry/exporter-collector-grpc

## Traces in Node - GRPC

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

```js
const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/tracing');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
import { MetricRecord, MetricExporter } from '@opentelemetry/metrics';
import { CollectorExporterConfigNode, ServiceClientType } from './types';
import { CollectorExporterNodeBase } from './CollectorExporterNodeBase';
import { getEnv } from '@opentelemetry/core';

const DEFAULT_SERVICE_NAME = 'collector-metric-exporter';
const DEFAULT_COLLECTOR_URL = 'localhost:4317';
Expand All @@ -47,11 +48,14 @@ export class CollectorMetricExporter
);
}

getDefaultUrl(config: CollectorExporterConfigNode): string {
if (!config.url) {
return DEFAULT_COLLECTOR_URL;
}
return config.url;
getDefaultUrl(config: CollectorExporterConfigNode) {
return typeof config.url === 'string'
? config.url
: getEnv().OTEL_EXPORTER_OTLP_METRICS_ENDPOINT.length > 0
? getEnv().OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
: getEnv().OTEL_EXPORTER_OTLP_ENDPOINT.length > 0
? getEnv().OTEL_EXPORTER_OTLP_ENDPOINT
: DEFAULT_COLLECTOR_URL;
}

getDefaultServiceName(config: CollectorExporterConfigNode): string {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
toCollectorExportTraceServiceRequest,
} from '@opentelemetry/exporter-collector';
import { CollectorExporterConfigNode, ServiceClientType } from './types';
import { getEnv } from '@opentelemetry/core';

const DEFAULT_SERVICE_NAME = 'collector-trace-exporter';
const DEFAULT_COLLECTOR_URL = 'localhost:4317';
Expand All @@ -40,11 +41,14 @@ export class CollectorTraceExporter
return toCollectorExportTraceServiceRequest(spans, this);
}

getDefaultUrl(config: CollectorExporterConfigNode): string {
if (!config.url) {
return DEFAULT_COLLECTOR_URL;
}
return config.url;
getDefaultUrl(config: CollectorExporterConfigNode) {
return typeof config.url === 'string'
? config.url
: getEnv().OTEL_EXPORTER_OTLP_TRACES_ENDPOINT.length > 0
? getEnv().OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
: getEnv().OTEL_EXPORTER_OTLP_ENDPOINT.length > 0
? getEnv().OTEL_EXPORTER_OTLP_ENDPOINT
: DEFAULT_COLLECTOR_URL;
}

getDefaultServiceName(config: CollectorExporterConfigNode): string {
Expand Down
Loading