Skip to content

Commit

Permalink
feat: add OTEL_LOG_LEVEL env var (open-telemetry#974)
Browse files Browse the repository at this point in the history
  • Loading branch information
Naseem authored and jonahrosenblum committed Aug 6, 2020
1 parent 7c09806 commit b956e9c
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 12 deletions.
3 changes: 2 additions & 1 deletion packages/opentelemetry-core/src/common/ConsoleLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@

import { Logger } from '@opentelemetry/api';
import { LogLevel } from './types';
import { getEnv } from '../platform';

export class ConsoleLogger implements Logger {
constructor(level: LogLevel = LogLevel.INFO) {
constructor(level: LogLevel = getEnv().OTEL_LOG_LEVEL) {
if (level >= LogLevel.DEBUG) {
this.debug = (...args) => {
console.debug(...args);
Expand Down
6 changes: 6 additions & 0 deletions packages/opentelemetry-core/src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ export enum LogLevel {
DEBUG,
}

/**
* This is equivalent to:
* type LogLevelString = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
*/
export type LogLevelString = keyof typeof LogLevel;

/**
* This interface defines a fallback to read a timeOrigin when it is not available on performance.timeOrigin,
* this happens for example on Safari Mac
Expand Down
40 changes: 37 additions & 3 deletions packages/opentelemetry-core/src/utils/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ export interface ENVIRONMENT {
}

const ENVIRONMENT_NUMBERS: Partial<keyof ENVIRONMENT>[] = [
'OTEL_LOG_LEVEL',
'OTEL_SAMPLING_PROBABILITY',
];

Expand All @@ -37,7 +36,7 @@ const ENVIRONMENT_NUMBERS: Partial<keyof ENVIRONMENT>[] = [
*/
export const DEFAULT_ENVIRONMENT: Required<ENVIRONMENT> = {
OTEL_NO_PATCH_MODULES: '',
OTEL_LOG_LEVEL: LogLevel.ERROR,
OTEL_LOG_LEVEL: LogLevel.INFO,
OTEL_SAMPLING_PROBABILITY: 1,
};

Expand All @@ -64,6 +63,41 @@ function parseNumber(
}
}

/**
* Environmentally sets log level if valid log level string is provided
* @param key
* @param environment
* @param values
*/
function setLogLevelFromEnv(
key: keyof ENVIRONMENT,
environment: ENVIRONMENT_MAP | ENVIRONMENT,
values: ENVIRONMENT_MAP
) {
const value = values[key];
switch (typeof value === 'string' ? value.toUpperCase() : value) {
case 'DEBUG':
environment[key] = LogLevel.DEBUG;
break;

case 'INFO':
environment[key] = LogLevel.INFO;
break;

case 'WARN':
environment[key] = LogLevel.WARN;
break;

case 'ERROR':
environment[key] = LogLevel.ERROR;
break;

default:
// do nothing
break;
}
}

/**
* Parses environment values
* @param values
Expand All @@ -79,7 +113,7 @@ export function parseEnvironment(values: ENVIRONMENT_MAP): ENVIRONMENT {
break;

case 'OTEL_LOG_LEVEL':
parseNumber(key, environment, values, LogLevel.ERROR, LogLevel.DEBUG);
setLogLevelFromEnv(key, environment, values);
break;

default:
Expand Down
37 changes: 37 additions & 0 deletions packages/opentelemetry-core/test/common/ConsoleLogger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
import * as assert from 'assert';
import { ConsoleLogger } from '../../src/common/ConsoleLogger';
import { LogLevel } from '../../src/common/types';
import {
mockEnvironment,
removeMockEnvironment,
} from '../utils/environment.test';

describe('ConsoleLogger', () => {
const origDebug = console.debug;
Expand Down Expand Up @@ -54,6 +58,7 @@ describe('ConsoleLogger', () => {
console.info = origInfo;
console.warn = origWarn;
console.error = origError;
removeMockEnvironment();
});

describe('constructor', () => {
Expand All @@ -65,6 +70,8 @@ describe('ConsoleLogger', () => {
assert.deepStrictEqual(warnCalledArgs, ['warn called %s', 'param1']);
consoleLogger.info('info called %s', 'param1');
assert.deepStrictEqual(infoCalledArgs, ['info called %s', 'param1']);
consoleLogger.debug('debug called %s', 'param1');
assert.strictEqual(debugCalledArgs, undefined);
});

it('should log with debug', () => {
Expand Down Expand Up @@ -114,5 +121,35 @@ describe('ConsoleLogger', () => {
consoleLogger.debug('debug called %s', 'param1');
assert.strictEqual(debugCalledArgs, null);
});

it('should log with environmentally set level ', () => {
mockEnvironment({
OTEL_LOG_LEVEL: 'WARN',
});
const consoleLogger = new ConsoleLogger();
consoleLogger.error('error called');
assert.deepStrictEqual(errorCalledArgs, ['error called']);
consoleLogger.warn('warn called %s', 'param1');
assert.deepStrictEqual(warnCalledArgs, ['warn called %s', 'param1']);
consoleLogger.info('info called %s', 'param1');
assert.deepStrictEqual(infoCalledArgs, null);
consoleLogger.debug('debug called %s', 'param1');
assert.deepStrictEqual(debugCalledArgs, null);
});

it('should log with default log level if environmentally set level is invalid', () => {
mockEnvironment({
OTEL_LOG_LEVEL: 'INVALID_VALUE',
});
const consoleLogger = new ConsoleLogger();
consoleLogger.error('error called');
assert.deepStrictEqual(errorCalledArgs, ['error called']);
consoleLogger.warn('warn called %s', 'param1');
assert.deepStrictEqual(warnCalledArgs, ['warn called %s', 'param1']);
consoleLogger.info('info called %s', 'param1');
assert.deepStrictEqual(infoCalledArgs, ['info called %s', 'param1']);
consoleLogger.debug('debug called %s', 'param1');
assert.deepStrictEqual(debugCalledArgs, null);
});
});
});
36 changes: 32 additions & 4 deletions packages/opentelemetry-core/test/utils/environment.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@ import {
} from '../../src/utils/environment';
import * as assert from 'assert';
import * as sinon from 'sinon';
import { LogLevel } from '../../src';

let lastMock: ENVIRONMENT_MAP = {};

function mockEnvironment(values: ENVIRONMENT_MAP) {
/**
* Mocks environment used for tests.
*/
export function mockEnvironment(values: ENVIRONMENT_MAP) {
lastMock = values;
if (typeof process !== 'undefined') {
Object.keys(values).forEach(key => {
Expand All @@ -38,7 +42,10 @@ function mockEnvironment(values: ENVIRONMENT_MAP) {
}
}

function removeMockEnvironment() {
/**
* Removes mocked environment used for tests.
*/
export function removeMockEnvironment() {
if (typeof process !== 'undefined') {
Object.keys(lastMock).forEach(key => {
delete process.env[key];
Expand Down Expand Up @@ -68,15 +75,23 @@ describe('environment', () => {
mockEnvironment({
FOO: '1',
OTEL_NO_PATCH_MODULES: 'a,b,c',
OTEL_LOG_LEVEL: '1',
OTEL_LOG_LEVEL: 'ERROR',
OTEL_SAMPLING_PROBABILITY: '0.5',
});
const env = getEnv();
assert.strictEqual(env.OTEL_NO_PATCH_MODULES, 'a,b,c');
assert.strictEqual(env.OTEL_LOG_LEVEL, 1);
assert.strictEqual(env.OTEL_LOG_LEVEL, LogLevel.ERROR);
assert.strictEqual(env.OTEL_SAMPLING_PROBABILITY, 0.5);
});

it('should parse OTEL_LOG_LEVEL despite casing', () => {
mockEnvironment({
OTEL_LOG_LEVEL: 'waRn',
});
const env = getEnv();
assert.strictEqual(env.OTEL_LOG_LEVEL, LogLevel.WARN);
});

it('should parse environment variables and use defaults', () => {
const env = getEnv();
Object.keys(DEFAULT_ENVIRONMENT).forEach(envKey => {
Expand All @@ -89,4 +104,17 @@ describe('environment', () => {
});
});
});

describe('mockEnvironment', () => {
it('should remove a mock environment', () => {
mockEnvironment({
OTEL_LOG_LEVEL: 'DEBUG',
OTEL_SAMPLING_PROBABILITY: 0.5,
});
removeMockEnvironment();
const env = getEnv();
assert.strictEqual(env.OTEL_LOG_LEVEL, LogLevel.INFO);
assert.strictEqual(env.OTEL_SAMPLING_PROBABILITY, 1);
});
});
});
4 changes: 2 additions & 2 deletions packages/opentelemetry-metrics/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import { LogLevel } from '@opentelemetry/core';
import { LogLevel, getEnv } from '@opentelemetry/core';
import * as api from '@opentelemetry/api';
import { MetricExporter } from './export/types';
import { Resource } from '@opentelemetry/resources';
Expand Down Expand Up @@ -46,7 +46,7 @@ export interface MeterConfig {

/** Default Meter configuration. */
export const DEFAULT_CONFIG = {
logLevel: LogLevel.INFO,
logLevel: getEnv().OTEL_LOG_LEVEL,
gracefulShutdown: true,
};

Expand Down
4 changes: 2 additions & 2 deletions packages/opentelemetry-tracing/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import { AlwaysOnSampler, LogLevel } from '@opentelemetry/core';
import { AlwaysOnSampler, getEnv } from '@opentelemetry/core';

/** Default limit for Message events per span */
export const DEFAULT_MAX_EVENTS_PER_SPAN = 128;
Expand All @@ -30,7 +30,7 @@ export const DEFAULT_MAX_LINKS_PER_SPAN = 32;
* used to extend the default value.
*/
export const DEFAULT_CONFIG = {
logLevel: LogLevel.INFO,
logLevel: getEnv().OTEL_LOG_LEVEL,
sampler: new AlwaysOnSampler(),
traceParams: {
numberOfAttributesPerSpan: DEFAULT_MAX_ATTRIBUTES_PER_SPAN,
Expand Down

0 comments on commit b956e9c

Please sign in to comment.