Skip to content
This repository has been archived by the owner on Jun 21, 2023. It is now read-only.

Commit

Permalink
Merge ef2bc79 into 5fd9f0e
Browse files Browse the repository at this point in the history
  • Loading branch information
vlasy committed Sep 22, 2020
2 parents 5fd9f0e + ef2bc79 commit 416f502
Show file tree
Hide file tree
Showing 11 changed files with 46 additions and 53 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
},
"dependencies": {
"@types/express": "^4.16.0",
"@types/pino": "^6.0.0",
"@types/pino": "^6.3.1",
"lodash.foreach": "^4.5.0",
"lodash.isempty": "^4.4.0",
"lodash.isobject": "^3.0.2",
Expand All @@ -40,7 +40,7 @@
"on-finished": "^2.3.0",
"on-headers": "^1.0.1",
"pick-deep": "^1.0.0",
"pino": "^6.2.0",
"pino": "^6.6.1",
"pino-multi-stream": "^5.0.0"
},
"peerDependencies": {
Expand Down
2 changes: 1 addition & 1 deletion src/express.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const expressOnFinished = (logger: Cosmas, req: AckeeRequest) => (_err: Error |
logFunction.call(logger, output.data, output.message);
};

const expressMiddleware: RequestHandler = function(
const expressMiddleware: RequestHandler = function (
this: Cosmas,
req: AckeeRequest,
response: AckeeResponse,
Expand Down
9 changes: 1 addition & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,6 @@ const defaultLogger = (options: CosmasOptions & { loggerName?: string } = {}): C
serializers.disablePaths(options.disableFields);
serializers.enablePaths(options.enableFields);

if (options.sentry) {
const sentry = require('@sentry/node');
if (typeof options.sentry === 'string') {
sentry.init({ dsn: options.sentry });
}
}

const isTesting = process.env.NODE_ENV === 'test';
const defaultLevel: Level = options.defaultLevel || (isTesting ? 'silent' : 'debug');
const messageKey = 'message'; // best option for Google Stackdriver,
Expand Down Expand Up @@ -202,6 +195,6 @@ const loggerFactory = (data: string | CosmasOptions = {}, loggerOptions: CosmasO
return loggerProxy;
};

const factoryProxy = makeCallable(loggerFactory(), loggerFactory);
const factoryProxy: CosmasFactory = makeCallable(loggerFactory(), loggerFactory);

export default factoryProxy;
2 changes: 0 additions & 2 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ export interface CosmasOptions {
ignoredHttpMethods?: string[];
config?: LoggerOptions;
pretty?: boolean;
sentry?: string | boolean;
sentryLevel?: pino.LevelWithSilent;
loggerName?: string;
skip?: (req: Request, res?: Response) => boolean;
}
37 changes: 20 additions & 17 deletions src/sentry.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { captureException, captureMessage, Severity, withScope } from '@sentry/node';
import { Transform, TransformCallback } from 'stream';
import { CosmasOptions } from './interfaces';
import * as pino from 'pino';
import { Cosmas } from '.';
import { levels } from './levels';

const reportToSentry = (obj: any) => {
Expand All @@ -23,20 +23,23 @@ const PINO_TO_SENTRY: { [key: number]: Severity } = {
60: Severity.Critical,
};

export const createSentryTransformStream = (options: CosmasOptions): any => {
return class SentryTransformStream extends Transform {
// tslint:disable-next-line:function-name
public _transform(chunk: any, _encoding: string, callback: TransformCallback) {
const obj = JSON.parse(chunk);
if (obj.level >= (options.sentryLevel || levels.warn)) {
withScope(scope => {
scope.setLevel(PINO_TO_SENTRY[obj.level]);
scope.setExtras(obj);
reportToSentry(obj);
});
}
this.push(chunk);
callback();
}
export const extendSentry = (logger: Cosmas, options: { sentry: string | true; sentryLevel: number }) => {
const sentry = require('@sentry/node');
if (typeof options.sentry === 'string') {
sentry.init({ dsn: options.sentry });
}

const originalWrite = (logger as any)[pino.symbols.streamSym].write;
// unfortunately, this is the only place in pino, we can hook onto, where we can be sure all
// the hooks, formatters and serializers are already applied
(logger as any)[pino.symbols.streamSym].write = function (s: string) {
originalWrite.call(this, s);
const obj = JSON.parse(s);
if (obj.level < (options.sentryLevel || levels.warn)) return;
withScope((scope) => {
scope.setLevel(PINO_TO_SENTRY[obj.level]);
scope.setExtras(obj);
reportToSentry(obj);
});
};
};
4 changes: 2 additions & 2 deletions src/serializers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const serializers: Dictionary<SerializerFn> = {
},
req(obj: Dictionary<any>): Dictionary<any> {
const pickHeaders = ['x-deviceid', 'authorization', 'user-agent'];
const [body, query] = ['body', 'query'].map(name => {
const [body, query] = ['body', 'query'].map((name) => {
const source = obj[name];
if (source) {
const rest = Object.assign({}, source);
Expand All @@ -55,7 +55,7 @@ const serializers: Dictionary<SerializerFn> = {
};

const sliceByPrefix = (prefix: string, paths?: string[]) =>
(paths || []).filter(field => field.startsWith(prefix)).map(field => field.slice(prefix.length));
(paths || []).filter((field) => field.startsWith(prefix)).map((field) => field.slice(prefix.length));

const disablePaths = (paths?: string[]) => {
forEach(serializers, (value, key) => {
Expand Down
9 changes: 2 additions & 7 deletions src/streams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const getDefaultTransformStream = (options: CosmasOptions & { messageKey: string
};

const decorateStreams = <T extends Transform>(streams: CosmasStream[], streamClass: new () => T) => {
return streams.map(stream => {
return streams.map((stream) => {
const newStream = new streamClass();
newStream.pipe(stream.stream);
return {
Expand All @@ -42,7 +42,7 @@ const initLoggerStreams = (
) => {
let streams: CosmasStream[];
if (options.streams) {
streams = options.streams.map(stream => Object.assign({ level: defaultLevel }, stream));
streams = options.streams.map((stream) => Object.assign({ level: defaultLevel }, stream));
} else {
streams = [
{ level: defaultLevel, maxLevel: levels.warn, stream: process.stdout },
Expand All @@ -52,11 +52,6 @@ const initLoggerStreams = (

streams = decorateStreams(streams, getDefaultTransformStream(options));

if (options.sentry) {
const { createSentryTransformStream } = require('./sentry');
streams = decorateStreams(streams, createSentryTransformStream(options));
}

return streams;
};

Expand Down
4 changes: 2 additions & 2 deletions src/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,14 @@ test('Child logger takes parent config', () => {
});

test('Child logger inherits parent name', () => {
const logger = loggerFactory('parent', { disableStackdriverFormat: true });
const logger = loggerFactory('parent');
const childLogger = logger('child');

expect(childLogger.options.loggerName).toBe('parentchild');
});

test('Child logger can create another child', () => {
const logger = loggerFactory('parent', { disableStackdriverFormat: true });
const logger = loggerFactory('parent');
const childLogger = logger('child');
const kid = childLogger('grandkid');

Expand Down
17 changes: 10 additions & 7 deletions src/tests/sentry-mocked.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import omit = require('omit-deep');
import { CosmasFactory } from '../index';
import { levels } from '../levels';

let loggerFactory;
let loggerFactory: CosmasFactory;
let extendSentry;
const scope: any = {};
const withScope = jest.fn((fn) =>
fn({
Expand Down Expand Up @@ -44,16 +46,17 @@ describe('sentry mocked', () => {
};
});
loggerFactory = require('../index').default;
extendSentry = require('../sentry').extendSentry;
});
beforeEach(() => {
captureException.mockReset();
captureMessage.mockReset();
});
test('can create logger with options', () => {
expect(() => loggerFactory()).not.toThrowError();
expect(() => loggerFactory({ sentry: true })).not.toThrowError();
expect(() => extendSentry(loggerFactory, { sentry: true })).not.toThrowError();
expect(init).not.toHaveBeenCalled();
expect(() => loggerFactory({ sentry: 'dummy' })).not.toThrowError();
expect(() => extendSentry(loggerFactory, { sentry: 'dummy' })).not.toThrowError();
expect(init.mock.calls[0]).toMatchInlineSnapshot(`
Array [
Object {
Expand All @@ -67,7 +70,8 @@ describe('sentry mocked', () => {
const dateNow = Date.now;
Date.now = jest.fn(() => 1520343036000);
await new Promise((resolve, reject) => {
const logger = loggerFactory({
const logger = loggerFactory();
extendSentry(logger, {
sentry: 'DSN',
sentryLevel: levels.fatal,
});
Expand Down Expand Up @@ -107,9 +111,8 @@ Object {

test('sentry captureException with stack and correct levels', async () => {
await new Promise((resolve, reject) => {
const logger = loggerFactory({
sentry: 'DSN',
});
const logger = loggerFactory();
extendSentry(logger, { sentry: 'DSN' });
captureException.mockReset();
captureException.mockImplementation(createCapture(resolve));
logger.error(new Error());
Expand Down
9 changes: 5 additions & 4 deletions src/tests/sentry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import loggerFactory from '../index';
describe('sentry not available', () => {
beforeAll(() => {
jest.mock('@sentry/node', () => {
throw new Error("Cannot find module '@sentry/node' from 'index.ts'");
throw new Error("Cannot find module '@sentry/node' from 'sentry.ts'");
});
});
test('without sentry lib works by default, but crashes on provided', () => {
expect(() => loggerFactory()).not.toThrowError();
expect(() => loggerFactory({ sentry: 'DSN' })).toThrowErrorMatchingInlineSnapshot(
`"Cannot find module '@sentry/node' from 'index.ts'"`
);
expect(() => {
const extendSentry = require('../sentry').extendSentry;
extendSentry(loggerFactory);
}).toThrowErrorMatchingInlineSnapshot(`"Cannot find module '@sentry/node' from 'sentry.ts'"`);
});
});
2 changes: 1 addition & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import omit = require('omit-deep');
const removeEmpty = (obj: Dictionary<any>): object =>
omit(
obj,
Object.keys(obj).filter(key => obj[key] === undefined || isEmpty(obj[key]))
Object.keys(obj).filter((key) => obj[key] === undefined || isEmpty(obj[key]))
);

const matchPath = (pattern: RegExp) => (req: Request): boolean => req.originalUrl.match(pattern) !== null;
Expand Down

0 comments on commit 416f502

Please sign in to comment.