Skip to content

Commit

Permalink
feat: better diagnostic logging configuration (#605)
Browse files Browse the repository at this point in the history
* feat: better diagnostic logging

* test: prefer api over env var
  • Loading branch information
seemk authored Nov 16, 2022
1 parent c141e58 commit 0990fb3
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 18 deletions.
22 changes: 5 additions & 17 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,15 @@

Diagnostic logs can help you troubleshoot instrumentation issues.

To output instrumentation logs to the console, add `DiagConsoleLogger` and `DiagLogLevel`:
To enable diagnostic logging, set the `logLevel` option or `OTEL_LOG_LEVEL` environment variable to `debug`.

```javascript
const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api');

diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ALL);
```
Available values, from least to most detailed, are `error`, `warn`, `info`, `debug`, `verbose`.

Logging level is controlled by the `OTEL_LOG_LEVEL` environment variable. Available values, from least to most detailed, are:

- `ERROR`: Identifies errors.
- `WARN`: Identifies warnings.
- `INFO`: Informational messages. This is the default level.
- `DEBUG`: Debug log messages.
- `VERBOSE`: Detailed trace level logging.

To set the logger back to a noop:
To disable logging after it has been enabled:

```javascript

diag.setLogger();
const { diag } = require('@opentelemetry/api');
diag.setLogger();
```

> Enable debug logging only when needed. Debug mode requires more resources.
Expand Down
19 changes: 18 additions & 1 deletion src/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { assertNoExtraneousProperties, parseEnvBooleanString } from './utils';
import {
assertNoExtraneousProperties,
parseEnvBooleanString,
parseLogLevel,
toDiagLogLevel,
} from './utils';
import { startMetrics, StartMetricsOptions } from './metrics';
import {
startProfiling,
StartProfilingOptions,
_setDefaultOptions as setDefaultProfilingOptions,
} from './profiling';
import type { LogLevel } from './types';
import { startTracing, stopTracing, StartTracingOptions } from './tracing';
import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api';

interface Options {
accessToken: string;
endpoint: string;
serviceName: string;
logLevel?: LogLevel;
// Signal-specific configuration options:
metrics: boolean | StartMetricsOptions;
profiling: boolean | StartProfilingOptions;
Expand Down Expand Up @@ -62,8 +70,17 @@ export const start = (options: Partial<Options> = {}) => {
'accessToken',
'endpoint',
'serviceName',
'logLevel',
]);

const logLevel = options.logLevel
? toDiagLogLevel(options.logLevel)
: parseLogLevel(process.env.OTEL_LOG_LEVEL);

if (logLevel !== DiagLogLevel.NONE) {
diag.setLogger(new DiagConsoleLogger(), logLevel);
}

let metricsEnabledByDefault = false;
if (isSignalEnabled(options.profiling, 'SPLUNK_PROFILER_ENABLED', false)) {
const profilingOptions = Object.assign({}, restOptions, profiling);
Expand Down
17 changes: 17 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright Splunk Inc.
*
* 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
*
* http://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 type LogLevel = 'none' | 'verbose' | 'debug' | 'info' | 'warn' | 'error';
37 changes: 37 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/

import { strict as assert } from 'assert';
import { DiagLogLevel } from '@opentelemetry/api';
import type { LogLevel } from './types';

export const defaultServiceName = 'unnamed-node-service';

Expand Down Expand Up @@ -116,3 +118,38 @@ export function assertNoExtraneousProperties(
)}. Allowed: ${formatStringSet(expectedProps)}`
);
}

function validLogLevel(level: string): level is LogLevel {
return ['verbose', 'debug', 'info', 'warn', 'error'].includes(level);
}

export function toDiagLogLevel(level: LogLevel): DiagLogLevel {
switch (level) {
case 'verbose':
return DiagLogLevel.VERBOSE;
case 'debug':
return DiagLogLevel.DEBUG;
case 'info':
return DiagLogLevel.INFO;
case 'warn':
return DiagLogLevel.WARN;
case 'error':
return DiagLogLevel.ERROR;
}

return DiagLogLevel.NONE;
}

export function parseLogLevel(value: string | undefined): DiagLogLevel {
if (value === undefined) {
return DiagLogLevel.NONE;
}

const v = value.trim().toLowerCase();

if (validLogLevel(v)) {
return toDiagLogLevel(v);
}

return DiagLogLevel.NONE;
}
47 changes: 47 additions & 0 deletions test/start.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import * as profiling from '../src/profiling';
import * as tracing from '../src/tracing';
import { start, stop } from '../src';
import { Resource } from '@opentelemetry/resources';
import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api';

import * as utils from './utils';

Expand Down Expand Up @@ -209,4 +210,50 @@ describe('start', () => {
assertCalled(signals.start, []);
});
});

describe('diagnostic logging', () => {
const sandbox = sinon.createSandbox();
let c;

beforeEach(() => {
utils.cleanEnvironment();
c = sandbox.spy(console);
});

afterEach(() => {
sandbox.restore();
});

it('does not enable diagnostic logging by default', () => {
start();
diag.info('42');
assert(c.log.notCalled);
});

it('does not enable diagnostic logging via explicit config', () => {
start({ logLevel: 'none' });
diag.info('42');
assert(c.log.notCalled);
});

it('is possible to enable diag logging via config', () => {
start({ logLevel: 'debug' });
diag.debug('42');
assert(c.debug.calledWithExactly('42'));
});

it('is possible to enable diag logging via env vars', () => {
process.env.OTEL_LOG_LEVEL = 'info';
start();
diag.info('42');
assert(c.info.calledWithExactly('42'));
});

it('prefers programmatic config over env var', () => {
process.env.OTEL_LOG_LEVEL = 'debug';
start({ logLevel: 'info' });
diag.debug('42');
assert(c.debug.notCalled);
});
});
});
36 changes: 36 additions & 0 deletions test/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright Splunk Inc.
*
* 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
*
* http://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 * as assert from 'assert';

import { parseLogLevel } from '../src/utils';
import { cleanEnvironment } from './utils';
import { DiagLogLevel } from '@opentelemetry/api';

describe('utils', () => {
describe('logLevel', () => {
it('can parse log levels', () => {
assert.deepStrictEqual(parseLogLevel('none'), DiagLogLevel.NONE);
assert.deepStrictEqual(parseLogLevel('abc'), DiagLogLevel.NONE);
assert.deepStrictEqual(parseLogLevel('verbose'), DiagLogLevel.VERBOSE);
assert.deepStrictEqual(parseLogLevel('debug'), DiagLogLevel.DEBUG);
assert.deepStrictEqual(parseLogLevel('info'), DiagLogLevel.INFO);
assert.deepStrictEqual(parseLogLevel('warn'), DiagLogLevel.WARN);
assert.deepStrictEqual(parseLogLevel('error'), DiagLogLevel.ERROR);
assert.deepStrictEqual(parseLogLevel(' error'), DiagLogLevel.ERROR);
assert.deepStrictEqual(parseLogLevel('ERROR'), DiagLogLevel.ERROR);
});
});
});

0 comments on commit 0990fb3

Please sign in to comment.