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(instrumentation-winston): Allow log level to be configured for log sending #2016

Merged
merged 10 commits into from
Apr 19, 2024
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ logger.info('foobar');
| Option | Type | Description |
| ----------------------- | ----------------- | ----------- |
| `disableLogSending` | `boolean` | Whether to disable [log sending](#log-sending). Default `false`. |
| `logSeverity` | `SeverityNumber` | Control severity level for [log sending](#log-sending). Default `SeverityNumber.UNSPECIFIED`, it will use Winston Logger's current level when unspecified. |
| `disableLogCorrelation` | `boolean` | Whether to disable [log correlation](#log-correlation). Default `false`. |
| `logHook` | `LogHookFunction` | An option hook to inject additional context to a log record after trace-context has been added. This requires `disableLogCorrelation` to be false. |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"winston2": "npm:winston@2.4.7"
},
"dependencies": {
"@opentelemetry/api-logs": "^0.50.0",
"@opentelemetry/instrumentation": "^0.50.0"
},
"homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/plugins/node/opentelemetry-instrumentation-winston#readme"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import { context, trace, isSpanContextValid, Span } from '@opentelemetry/api';
import { SeverityNumber } from '@opentelemetry/api-logs';
import {
InstrumentationBase,
InstrumentationNodeModuleDefinition,
Expand Down Expand Up @@ -206,7 +207,17 @@
let newTransports = Array.isArray(originalTransports)
? originalTransports
: [];
const openTelemetryTransport = new OpenTelemetryTransportV3();
let transportOptions = {};
if (config.logSeverity) {
const winstonLevel = instrumentation._winstonLevelFromSeverity(
config.logSeverity,
args[0].levels
);
transportOptions = { level: winstonLevel };
}
const openTelemetryTransport = new OpenTelemetryTransportV3(
transportOptions
);
if (originalTransports && !Array.isArray(originalTransports)) {
newTransports = [originalTransports];
}
Expand Down Expand Up @@ -244,4 +255,118 @@
}
return record;
}

private _winstonLevelFromSeverity(
severity: SeverityNumber,
winstonLevels: { [key: string]: number } | undefined
): string | undefined {
if (winstonLevels) {
if (isNpmLevels(winstonLevels)) {
if (severity >= SeverityNumber.ERROR) {
return 'error';
} else if (severity >= SeverityNumber.WARN) {
return 'warn';
} else if (severity >= SeverityNumber.INFO) {
return 'info';
} else if (severity >= SeverityNumber.DEBUG3) {
return 'http';
} else if (severity >= SeverityNumber.DEBUG2) {
return 'verbose';
} else if (severity >= SeverityNumber.DEBUG) {
return 'debug';
} else if (severity >= SeverityNumber.TRACE) {
return 'silly';

Check warning on line 278 in plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts

View check run for this annotation

Codecov / codecov/patch

plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts#L267-L278

Added lines #L267 - L278 were not covered by tests
}
} else if (isCliLevels(winstonLevels)) {
if (severity >= SeverityNumber.ERROR) {
return 'error';

Check warning on line 282 in plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts

View check run for this annotation

Codecov / codecov/patch

plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts#L282

Added line #L282 was not covered by tests
} else if (severity >= SeverityNumber.WARN) {
return 'warn';
} else if (severity >= SeverityNumber.INFO3) {
return 'help';
} else if (severity >= SeverityNumber.INFO2) {
return 'data';
} else if (severity >= SeverityNumber.INFO) {
return 'info';
} else if (severity >= SeverityNumber.DEBUG) {
return 'debug';
} else if (severity >= SeverityNumber.TRACE4) {
return 'prompt';
} else if (severity >= SeverityNumber.TRACE3) {
return 'verbose';
} else if (severity >= SeverityNumber.TRACE2) {
return 'input';
} else if (severity >= SeverityNumber.TRACE) {
return 'silly';

Check warning on line 300 in plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts

View check run for this annotation

Codecov / codecov/patch

plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts#L285-L300

Added lines #L285 - L300 were not covered by tests
}
} else if (isSyslogLevels(winstonLevels)) {
if (severity >= SeverityNumber.FATAL2) {
return 'emerg';

Check warning on line 304 in plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts

View check run for this annotation

Codecov / codecov/patch

plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts#L304

Added line #L304 was not covered by tests
} else if (severity >= SeverityNumber.FATAL) {
return 'alert';

Check warning on line 306 in plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts

View check run for this annotation

Codecov / codecov/patch

plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts#L306

Added line #L306 was not covered by tests
} else if (severity >= SeverityNumber.ERROR2) {
return 'crit';

Check warning on line 308 in plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts

View check run for this annotation

Codecov / codecov/patch

plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts#L308

Added line #L308 was not covered by tests
} else if (severity >= SeverityNumber.ERROR) {
return 'error';

Check warning on line 310 in plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts

View check run for this annotation

Codecov / codecov/patch

plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts#L310

Added line #L310 was not covered by tests
} else if (severity >= SeverityNumber.WARN) {
return 'warning';
} else if (severity >= SeverityNumber.INFO2) {
return 'notice';
} else if (severity >= SeverityNumber.INFO) {
return 'info';
} else if (severity >= SeverityNumber.TRACE) {
return 'debug';

Check warning on line 318 in plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts

View check run for this annotation

Codecov / codecov/patch

plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts#L313-L318

Added lines #L313 - L318 were not covered by tests
}
}
// Unknown level
this._diag.warn(

Check warning on line 322 in plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts

View check run for this annotation

Codecov / codecov/patch

plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts#L322

Added line #L322 was not covered by tests
'failed to configure severity with existing winston levels'
);
}

function isCliLevels(arg: any): boolean {
return (
arg &&
arg.error !== undefined &&
arg.warn &&
arg.help &&
arg.data &&
arg.info &&
arg.debug &&
arg.prompt &&
arg.verbose &&
arg.input &&
arg.silly
);
}

function isNpmLevels(arg: any): boolean {
return (
arg &&
arg.error !== undefined &&
arg.warn &&
arg.info &&
arg.http &&
arg.verbose &&
arg.debug &&
arg.silly
);
}

function isSyslogLevels(arg: any): boolean {
return (
arg &&
arg.emerg !== undefined &&
arg.alert &&
arg.crit &&
arg.error &&
arg.warning &&
arg.notice &&
arg.info &&
arg.debug
);
}

return;

Check warning on line 370 in plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts

View check run for this annotation

Codecov / codecov/patch

plugins/node/opentelemetry-instrumentation-winston/src/instrumentation.ts#L370

Added line #L370 was not covered by tests
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import type {
export type Winston3LogMethod = Winston3Logger['write'];
export type Winston3ConfigureMethod = Winston3Logger['configure'];
export type { Winston3Logger };

export type { Winston2LogMethod };
export type Winston2LoggerModule = {
Logger: Winston2Logger & {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import { Span } from '@opentelemetry/api';
import { SeverityNumber } from '@opentelemetry/api-logs';
import { InstrumentationConfig } from '@opentelemetry/instrumentation';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -28,6 +29,11 @@ export interface WinstonInstrumentationConfig extends InstrumentationConfig {
*/
disableLogSending?: boolean;

/**
* Control Log sending severity level, logs will be sent for specified severity and higher.
*/
logSeverity?: SeverityNumber;

/**
* Whether to disable the injection trace-context fields, and possibly other
* fields from `logHook()`, into log records for log correlation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,4 +383,57 @@ describe('WinstonInstrumentation', () => {
}
});
});
describe('logSeverity config', () => {
beforeEach(() => {
instrumentation.setConfig({
disableLogSending: false,
});
memoryLogExporter.getFinishedLogRecords().length = 0; // clear
});

it('npm levels', () => {
if (!isWinston2) {
instrumentation.setConfig({
disableLogSending: false,
logSeverity: SeverityNumber.ERROR,
});
initLogger(LevelsType.npm);
logger.log('verbose', 'verbose');
logger.log('error', 'error');
const logRecords = memoryLogExporter.getFinishedLogRecords();
assert.strictEqual(logRecords.length, 1);
assert.strictEqual(logRecords[0].body, 'error');
}
});

it('cli levels', () => {
if (!isWinston2) {
instrumentation.setConfig({
disableLogSending: false,
logSeverity: SeverityNumber.WARN,
});
initLogger(LevelsType.cli);
logger.log('prompt', 'prompt');
logger.log('warn', 'warn');
const logRecords = memoryLogExporter.getFinishedLogRecords();
assert.strictEqual(logRecords.length, 1);
assert.strictEqual(logRecords[0].body, 'warn');
}
});

it('syslog levels', () => {
if (!isWinston2) {
instrumentation.setConfig({
disableLogSending: false,
logSeverity: SeverityNumber.WARN,
});
initLogger(LevelsType.syslog);
logger.log('notice', 'notice');
logger.log('emerg', 'emerg');
const logRecords = memoryLogExporter.getFinishedLogRecords();
assert.strictEqual(logRecords.length, 1);
assert.strictEqual(logRecords[0].body, 'emerg');
}
});
});
});
Loading