Skip to content

Commit

Permalink
Merge branch 'master' into propagaion-api-fields
Browse files Browse the repository at this point in the history
  • Loading branch information
dyladan authored Jan 13, 2021
2 parents 7497dbe + 139d9db commit c89ce15
Show file tree
Hide file tree
Showing 15 changed files with 272 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@
import {
DEFAULT_ENVIRONMENT,
ENVIRONMENT,
ENVIRONMENT_MAP,
RAW_ENVIRONMENT,
parseEnvironment,
} from '../../utils/environment';

/**
* Gets the environment variables
*/
export function getEnv(): Required<ENVIRONMENT> {
const _window = window as typeof window & ENVIRONMENT_MAP;
const _window = window as typeof window & RAW_ENVIRONMENT;
const globalEnv = parseEnvironment(_window);
return Object.assign({}, DEFAULT_ENVIRONMENT, globalEnv);
}
13 changes: 10 additions & 3 deletions packages/opentelemetry-core/src/platform/node/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,24 @@
* limitations under the License.
*/

import * as os from 'os';
import {
DEFAULT_ENVIRONMENT,
ENVIRONMENT,
ENVIRONMENT_MAP,
RAW_ENVIRONMENT,
parseEnvironment,
} from '../../utils/environment';

/**
* Gets the environment variables
*/
export function getEnv(): Required<ENVIRONMENT> {
const processEnv = parseEnvironment(process.env as ENVIRONMENT_MAP);
return Object.assign({}, DEFAULT_ENVIRONMENT, processEnv);
const processEnv = parseEnvironment(process.env as RAW_ENVIRONMENT);
return Object.assign(
{
HOSTNAME: os.hostname(),
},
DEFAULT_ENVIRONMENT,
processEnv
);
}
117 changes: 90 additions & 27 deletions packages/opentelemetry-core/src/utils/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,78 @@

import { LogLevel } from '../common/types';

export type ENVIRONMENT_MAP = { [key: string]: string | number };
const DEFAULT_LIST_SEPARATOR = ',';

/**
* Environment interface to define all names
*/
export interface ENVIRONMENT {
OTEL_LOG_LEVEL?: LogLevel;
OTEL_NO_PATCH_MODULES?: string;
OTEL_SAMPLING_PROBABILITY?: number;
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT?: number;
OTEL_SPAN_EVENT_COUNT_LIMIT?: number;
OTEL_SPAN_LINK_COUNT_LIMIT?: number;
OTEL_BSP_MAX_BATCH_SIZE?: number;
OTEL_BSP_SCHEDULE_DELAY_MILLIS?: number;
}

const ENVIRONMENT_NUMBERS: Partial<keyof ENVIRONMENT>[] = [
const ENVIRONMENT_NUMBERS_KEYS = [
'OTEL_BSP_MAX_BATCH_SIZE',
'OTEL_BSP_SCHEDULE_DELAY_MILLIS',
'OTEL_SAMPLING_PROBABILITY',
'OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT',
'OTEL_SPAN_EVENT_COUNT_LIMIT',
'OTEL_SPAN_LINK_COUNT_LIMIT',
'OTEL_BSP_MAX_BATCH_SIZE',
'OTEL_BSP_SCHEDULE_DELAY_MILLIS',
];
] as const;

type ENVIRONMENT_NUMBERS = {
[K in typeof ENVIRONMENT_NUMBERS_KEYS[number]]?: number;
};

function isEnvVarANumber(key: unknown): key is keyof ENVIRONMENT_NUMBERS {
return (
ENVIRONMENT_NUMBERS_KEYS.indexOf(key as keyof ENVIRONMENT_NUMBERS) > -1
);
}

const ENVIRONMENT_LISTS_KEYS = ['OTEL_NO_PATCH_MODULES'] as const;

type ENVIRONMENT_LISTS = {
[K in typeof ENVIRONMENT_LISTS_KEYS[number]]?: string[];
};

function isEnvVarAList(key: unknown): key is keyof ENVIRONMENT_LISTS {
return ENVIRONMENT_LISTS_KEYS.indexOf(key as keyof ENVIRONMENT_LISTS) > -1;
}

export type ENVIRONMENT = {
CONTAINER_NAME?: string;
ECS_CONTAINER_METADATA_URI_V4?: string;
ECS_CONTAINER_METADATA_URI?: string;
HOSTNAME?: string;
KUBERNETES_SERVICE_HOST?: string;
NAMESPACE?: string;
OTEL_EXPORTER_JAEGER_AGENT_HOST?: string;
OTEL_EXPORTER_JAEGER_ENDPOINT?: string;
OTEL_EXPORTER_JAEGER_PASSWORD?: string;
OTEL_EXPORTER_JAEGER_USER?: string;
OTEL_LOG_LEVEL?: LogLevel;
OTEL_RESOURCE_ATTRIBUTES?: string;
} & ENVIRONMENT_NUMBERS &
ENVIRONMENT_LISTS;

export type RAW_ENVIRONMENT = {
[key: string]: string | number | undefined | string[];
};

/**
* Default environment variables
*/
export const DEFAULT_ENVIRONMENT: Required<ENVIRONMENT> = {
OTEL_NO_PATCH_MODULES: '',
CONTAINER_NAME: '',
ECS_CONTAINER_METADATA_URI_V4: '',
ECS_CONTAINER_METADATA_URI: '',
HOSTNAME: '',
KUBERNETES_SERVICE_HOST: '',
NAMESPACE: '',
OTEL_EXPORTER_JAEGER_AGENT_HOST: '',
OTEL_EXPORTER_JAEGER_ENDPOINT: '',
OTEL_EXPORTER_JAEGER_PASSWORD: '',
OTEL_EXPORTER_JAEGER_USER: '',
OTEL_LOG_LEVEL: LogLevel.INFO,
OTEL_NO_PATCH_MODULES: [],
OTEL_RESOURCE_ATTRIBUTES: '',
OTEL_SAMPLING_PROBABILITY: 1,
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT: 1000,
OTEL_SPAN_EVENT_COUNT_LIMIT: 1000,
Expand All @@ -64,15 +105,14 @@ export const DEFAULT_ENVIRONMENT: Required<ENVIRONMENT> = {
* @param max
*/
function parseNumber(
name: keyof ENVIRONMENT,
environment: ENVIRONMENT_MAP | ENVIRONMENT,
values: ENVIRONMENT_MAP,
name: keyof ENVIRONMENT_NUMBERS,
environment: ENVIRONMENT,
values: RAW_ENVIRONMENT,
min = -Infinity,
max = Infinity
) {
if (typeof values[name] !== 'undefined') {
const value = Number(values[name] as string);

if (!isNaN(value)) {
if (value < min) {
environment[name] = min;
Expand All @@ -85,6 +125,25 @@ function parseNumber(
}
}

/**
* Parses list-like strings from input into output.
* @param name
* @param environment
* @param values
* @param separator
*/
function parseStringList(
name: keyof ENVIRONMENT_LISTS,
output: ENVIRONMENT,
input: RAW_ENVIRONMENT,
separator = DEFAULT_LIST_SEPARATOR
) {
const givenValue = input[name];
if (typeof givenValue === 'string') {
output[name] = givenValue.split(separator).map(v => v.trim());
}
}

/**
* Environmentally sets log level if valid log level string is provided
* @param key
Expand All @@ -93,8 +152,8 @@ function parseNumber(
*/
function setLogLevelFromEnv(
key: keyof ENVIRONMENT,
environment: ENVIRONMENT_MAP | ENVIRONMENT,
values: ENVIRONMENT_MAP
environment: RAW_ENVIRONMENT | ENVIRONMENT,
values: RAW_ENVIRONMENT
) {
const value = values[key];
switch (typeof value === 'string' ? value.toUpperCase() : value) {
Expand Down Expand Up @@ -124,11 +183,12 @@ function setLogLevelFromEnv(
* Parses environment values
* @param values
*/
export function parseEnvironment(values: ENVIRONMENT_MAP): ENVIRONMENT {
const environment: ENVIRONMENT_MAP = {};
export function parseEnvironment(values: RAW_ENVIRONMENT): ENVIRONMENT {
const environment: ENVIRONMENT = {};

for (const env in DEFAULT_ENVIRONMENT) {
const key = env as keyof ENVIRONMENT;

switch (key) {
case 'OTEL_SAMPLING_PROBABILITY':
parseNumber(key, environment, values, 0, 1);
Expand All @@ -139,11 +199,14 @@ export function parseEnvironment(values: ENVIRONMENT_MAP): ENVIRONMENT {
break;

default:
if (ENVIRONMENT_NUMBERS.indexOf(key) >= 0) {
if (isEnvVarANumber(key)) {
parseNumber(key, environment, values);
} else if (isEnvVarAList(key)) {
parseStringList(key, environment, values);
} else {
if (typeof values[key] !== 'undefined') {
environment[key] = values[key];
const value = values[key];
if (typeof value !== 'undefined' && value !== null) {
environment[key] = String(value);
}
}
}
Expand Down
49 changes: 40 additions & 9 deletions packages/opentelemetry-core/test/utils/environment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,26 @@ import { getEnv } from '../../src/platform';
import {
DEFAULT_ENVIRONMENT,
ENVIRONMENT,
ENVIRONMENT_MAP,
RAW_ENVIRONMENT,
} from '../../src/utils/environment';
import * as assert from 'assert';
import * as sinon from 'sinon';
import { LogLevel } from '../../src';

let lastMock: ENVIRONMENT_MAP = {};
let lastMock: RAW_ENVIRONMENT = {};

/**
* Mocks environment used for tests.
*/
export function mockEnvironment(values: ENVIRONMENT_MAP) {
export function mockEnvironment(values: RAW_ENVIRONMENT) {
lastMock = values;
if (typeof process !== 'undefined') {
Object.keys(values).forEach(key => {
process.env[key] = String(values[key]);
});
} else {
Object.keys(values).forEach(key => {
((window as unknown) as ENVIRONMENT_MAP)[key] = String(values[key]);
((window as unknown) as RAW_ENVIRONMENT)[key] = String(values[key]);
});
}
}
Expand All @@ -52,7 +52,7 @@ export function removeMockEnvironment() {
});
} else {
Object.keys(lastMock).forEach(key => {
delete ((window as unknown) as ENVIRONMENT_MAP)[key];
delete ((window as unknown) as RAW_ENVIRONMENT)[key];
});
}
lastMock = {};
Expand All @@ -73,23 +73,54 @@ describe('environment', () => {
describe('parseEnvironment', () => {
it('should parse environment variables', () => {
mockEnvironment({
CONTAINER_NAME: 'container-1',
ECS_CONTAINER_METADATA_URI_V4: 'https://ecs.uri/v4',
ECS_CONTAINER_METADATA_URI: 'https://ecs.uri/',
FOO: '1',
OTEL_NO_PATCH_MODULES: 'a,b,c',
HOSTNAME: 'hostname',
KUBERNETES_SERVICE_HOST: 'https://k8s.host/',
NAMESPACE: 'namespace',
OTEL_BSP_MAX_BATCH_SIZE: 40,
OTEL_BSP_SCHEDULE_DELAY_MILLIS: 50,
OTEL_EXPORTER_JAEGER_AGENT_HOST: 'host.domain.com',
OTEL_EXPORTER_JAEGER_ENDPOINT: 'https://example.com/endpoint',
OTEL_EXPORTER_JAEGER_PASSWORD: 'secret',
OTEL_EXPORTER_JAEGER_USER: 'whoami',
OTEL_LOG_LEVEL: 'ERROR',
OTEL_NO_PATCH_MODULES: 'a,b,c',
OTEL_RESOURCE_ATTRIBUTES: '<attrs>',
OTEL_SAMPLING_PROBABILITY: '0.5',
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT: 10,
OTEL_SPAN_EVENT_COUNT_LIMIT: 20,
OTEL_SPAN_LINK_COUNT_LIMIT: 30,
OTEL_BSP_MAX_BATCH_SIZE: 40,
OTEL_BSP_SCHEDULE_DELAY_MILLIS: 50,
});
const env = getEnv();
assert.strictEqual(env.OTEL_NO_PATCH_MODULES, 'a,b,c');
assert.deepStrictEqual(env.OTEL_NO_PATCH_MODULES, ['a', 'b', 'c']);
assert.strictEqual(env.OTEL_LOG_LEVEL, LogLevel.ERROR);
assert.strictEqual(env.OTEL_SAMPLING_PROBABILITY, 0.5);
assert.strictEqual(env.OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, 10);
assert.strictEqual(env.OTEL_SPAN_EVENT_COUNT_LIMIT, 20);
assert.strictEqual(env.OTEL_SPAN_LINK_COUNT_LIMIT, 30);
assert.strictEqual(
env.OTEL_EXPORTER_JAEGER_ENDPOINT,
'https://example.com/endpoint'
);
assert.strictEqual(env.OTEL_EXPORTER_JAEGER_USER, 'whoami');
assert.strictEqual(env.OTEL_EXPORTER_JAEGER_PASSWORD, 'secret');
assert.strictEqual(
env.OTEL_EXPORTER_JAEGER_AGENT_HOST,
'host.domain.com'
);
assert.strictEqual(
env.ECS_CONTAINER_METADATA_URI_V4,
'https://ecs.uri/v4'
);
assert.strictEqual(env.ECS_CONTAINER_METADATA_URI, 'https://ecs.uri/');
assert.strictEqual(env.NAMESPACE, 'namespace');
assert.strictEqual(env.HOSTNAME, 'hostname');
assert.strictEqual(env.CONTAINER_NAME, 'container-1');
assert.strictEqual(env.KUBERNETES_SERVICE_HOST, 'https://k8s.host/');
assert.strictEqual(env.OTEL_RESOURCE_ATTRIBUTES, '<attrs>');
assert.strictEqual(env.OTEL_BSP_MAX_BATCH_SIZE, 40);
assert.strictEqual(env.OTEL_BSP_SCHEDULE_DELAY_MILLIS, 50);
});
Expand Down
2 changes: 1 addition & 1 deletion packages/opentelemetry-exporter-jaeger/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ npm install --save @opentelemetry/exporter-jaeger
Install the exporter on your application and pass the options, it must contain a service name.

Furthermore, the `host` option (which defaults to `localhost`), can instead be set by the
`JAEGER_AGENT_HOST` environment variable to reduce in-code config. If both are
`OTEL_EXPORTER_JAEGER_AGENT_HOST` environment variable to reduce in-code config. If both are
set, the value set by the option in code is authoritative.

```js
Expand Down
23 changes: 14 additions & 9 deletions packages/opentelemetry-exporter-jaeger/src/jaeger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import * as api from '@opentelemetry/api';
import { ExportResult, ExportResultCode } from '@opentelemetry/core';
import { ExportResult, ExportResultCode, getEnv } from '@opentelemetry/core';
import { ReadableSpan, SpanExporter } from '@opentelemetry/tracing';
import { Socket } from 'dgram';
import { spanToThrift } from './transform';
Expand Down Expand Up @@ -43,14 +43,19 @@ export class JaegerExporter implements SpanExporter {
: 2000;

// https://github.com/jaegertracing/jaeger-client-node#environment-variables
// By default, the client sends traces via UDP to the agent at localhost:6832. Use JAEGER_AGENT_HOST and
// JAEGER_AGENT_PORT to send UDP traces to a different host:port. If JAEGER_ENDPOINT is set, the client sends traces
// to the endpoint via HTTP, making the JAEGER_AGENT_HOST and JAEGER_AGENT_PORT unused. If JAEGER_ENDPOINT is secured,
// HTTP basic authentication can be performed by setting the JAEGER_USER and JAEGER_PASSWORD environment variables.
localConfig.endpoint = localConfig.endpoint || process.env.JAEGER_ENDPOINT;
localConfig.username = localConfig.username || process.env.JAEGER_USER;
localConfig.password = localConfig.password || process.env.JAEGER_PASSWORD;
localConfig.host = localConfig.host || process.env.JAEGER_AGENT_HOST;
// By default, the client sends traces via UDP to the agent at localhost:6832. Use OTEL_EXPORTER_JAEGER_AGENT_HOST and
// JAEGER_AGENT_PORT to send UDP traces to a different host:port. If OTEL_EXPORTER_JAEGER_ENDPOINT is set, the client sends traces
// to the endpoint via HTTP, making the OTEL_EXPORTER_JAEGER_AGENT_HOST and JAEGER_AGENT_PORT unused. If OTEL_EXPORTER_JAEGER_ENDPOINT is secured,
// HTTP basic authentication can be performed by setting the OTEL_EXPORTER_JAEGER_USER and OTEL_EXPORTER_JAEGER_PASSWORD environment variables.

const env = getEnv();
localConfig.endpoint =
localConfig.endpoint || env.OTEL_EXPORTER_JAEGER_ENDPOINT;
localConfig.username =
localConfig.username || env.OTEL_EXPORTER_JAEGER_USER;
localConfig.password =
localConfig.password || env.OTEL_EXPORTER_JAEGER_PASSWORD;
localConfig.host = localConfig.host || env.OTEL_EXPORTER_JAEGER_AGENT_HOST;
if (localConfig.endpoint) {
this._sender = new jaegerTypes.HTTPSender(localConfig);
} else {
Expand Down
Loading

0 comments on commit c89ce15

Please sign in to comment.