diff --git a/docs/docs/log.md b/docs/docs/log.md index 52f49f9..a76e5b1 100644 --- a/docs/docs/log.md +++ b/docs/docs/log.md @@ -38,15 +38,14 @@ if (somethingWrong) { ### Примеры использования -Подготовим логгер и обработчик для него. Для работы обработчику нужен Sentry Hub. +Подготовим логгер и обработчик для него. Для работы обработчику нужен Sentry Scope. ```ts -import { createLogger } from '@sima-land/isomorph/log'; -import { createSentryHandler } from '@sima-land/isomorph/log/handler/sentry'; -import { BrowserClient, Hub } from '@sentry/browser'; +import { createLogger, createSentryHandler } from '@sima-land/isomorph/log'; +import { BrowserClient, Scope } from '@sentry/browser'; const sentryClient = new BrowserClient({ dsn: process.env.SENTRY_DSN }); -const sentryHub = new Hub(sentryClient); +const sentryScope = new Scope(); // пустой scope в качестве примера const logger = createLogger(); diff --git a/docs/docs/tracing.md b/docs/docs/tracing.md index 61d1cc8..692ade4 100644 --- a/docs/docs/tracing.md +++ b/docs/docs/tracing.md @@ -10,4 +10,4 @@ sidebar_position: 4 ### DI-пресеты -TODO ссылки на разделы в документации по пресетам +WIP ссылки на разделы в документации по пресетам diff --git a/src/log/handler/__test__/pino.test.ts b/src/log/handler/__test__/pino.test.ts new file mode 100644 index 0000000..424cb55 --- /dev/null +++ b/src/log/handler/__test__/pino.test.ts @@ -0,0 +1,43 @@ +import pino from 'pino'; +import { createPinoHandler } from '../pino'; +import { createLogger } from '../../logger'; + +describe('createPinoHandler', () => { + it('should make handler properly', () => { + const stub: pino.Logger = { + info: jest.fn(), + warn: jest.fn(), + debug: jest.fn(), + error: jest.fn(), + } as unknown as pino.Logger; + + const logger = createLogger(); + + logger.subscribe(createPinoHandler(stub)); + + expect(stub.info).toHaveBeenCalledTimes(0); + logger.info('AAA'); + expect(stub.info).toHaveBeenCalledTimes(1); + expect(stub.info).toHaveBeenCalledWith('AAA'); + + expect(stub.info).toHaveBeenCalledTimes(1); + logger.log('AAA'); + expect(stub.info).toHaveBeenCalledTimes(2); + expect(stub.info).toHaveBeenCalledWith('AAA'); + + expect(stub.warn).toHaveBeenCalledTimes(0); + logger.warn('BBB'); + expect(stub.warn).toHaveBeenCalledTimes(1); + expect(stub.warn).toHaveBeenCalledWith('BBB'); + + expect(stub.debug).toHaveBeenCalledTimes(0); + logger.debug('CCC'); + expect(stub.debug).toHaveBeenCalledTimes(1); + expect(stub.debug).toHaveBeenCalledWith('CCC'); + + expect(stub.error).toHaveBeenCalledTimes(0); + logger.error('DDD'); + expect(stub.error).toHaveBeenCalledTimes(1); + expect(stub.error).toHaveBeenCalledWith('DDD'); + }); +}); diff --git a/src/log/handler/__test__/sentry.test.ts b/src/log/handler/__test__/sentry.test.ts new file mode 100644 index 0000000..dc1653b --- /dev/null +++ b/src/log/handler/__test__/sentry.test.ts @@ -0,0 +1,96 @@ +import { createSentryHandler } from '../sentry'; +import { createLogger } from '../../logger'; +import { Breadcrumb, DetailedError } from '../../errors'; +import type { Scope } from '@sentry/types'; + +describe('createSentryHandler', () => { + it('should handle function as scopeInit', () => { + const scope: Scope = { + setLevel: jest.fn(), + setContext: jest.fn(), + setExtra: jest.fn(), + captureException: jest.fn(), + addBreadcrumb: jest.fn(), + } as unknown as Scope; + + const getScope = jest.fn(() => scope); + + const logger = createLogger(); + + logger.subscribe(createSentryHandler(getScope)); + + expect(scope.captureException).toHaveBeenCalledTimes(0); + logger.error('fake error 1'); + logger.error('fake error 2'); + logger.error('fake error 3'); + expect(scope.captureException).toHaveBeenCalledTimes(3); + }); + + it('should make handler properly', () => { + const scope: Scope = { + setLevel: jest.fn(), + setContext: jest.fn(), + setExtra: jest.fn(), + captureException: jest.fn(), + addBreadcrumb: jest.fn(), + } as unknown as Scope; + + const logger = createLogger(); + + logger.subscribe(createSentryHandler(scope)); + + // error level with non DetailedError + expect(scope.captureException).toHaveBeenCalledTimes(0); + logger.error('fake error'); + expect(scope.captureException).toHaveBeenCalledTimes(1); + expect(scope.captureException).toHaveBeenCalledWith('fake error'); + + // error level with DetailedError with defined level + const error = new DetailedError('fake', { level: 'fatal' }); + expect(scope.setLevel).toHaveBeenCalledTimes(0); + expect(scope.captureException).toHaveBeenCalledTimes(1); + logger.error(error); + expect(scope.setLevel).toHaveBeenCalledTimes(1); + expect(scope.captureException).toHaveBeenCalledTimes(2); + expect(scope.captureException).toHaveBeenCalledWith(error); + + // error level with DetailedError with defined context + const error2 = new DetailedError('fake', { context: { key: 'CTX', data: {} } }); + expect(scope.setContext).toHaveBeenCalledTimes(0); + expect(scope.captureException).toHaveBeenCalledTimes(2); + logger.error(error2); + expect(scope.setContext).toHaveBeenCalledTimes(1); + expect(scope.captureException).toHaveBeenCalledTimes(3); + expect(scope.captureException).toHaveBeenCalledWith(error2); + + // error level with DetailedError with defined context as array + const error3 = new DetailedError('fake', { context: [{ key: 'CTX', data: {} }] }); + expect(scope.setContext).toHaveBeenCalledTimes(1); + expect(scope.captureException).toHaveBeenCalledTimes(3); + logger.error(error3); + expect(scope.setContext).toHaveBeenCalledTimes(2); + expect(scope.captureException).toHaveBeenCalledTimes(4); + expect(scope.captureException).toHaveBeenCalledWith(error3); + + // error level with DetailedError with defined extra + const error4 = new DetailedError('fake', { extra: { key: 'EXTRA', data: {} } }); + expect(scope.setExtra).toHaveBeenCalledTimes(0); + expect(scope.captureException).toHaveBeenCalledTimes(4); + logger.error(error4); + expect(scope.setExtra).toHaveBeenCalledTimes(1); + expect(scope.captureException).toHaveBeenCalledTimes(5); + expect(scope.captureException).toHaveBeenCalledWith(error4); + + // non error level with non Breadcrumb + expect(scope.captureException).toHaveBeenCalledTimes(5); + logger.info('hello'); + expect(scope.captureException).toHaveBeenCalledTimes(5); + + // non error level with Breadcrumb + const breadcrumb = new Breadcrumb({ category: 'test' }); + expect(scope.addBreadcrumb).toHaveBeenCalledTimes(0); + logger.info(breadcrumb); + expect(scope.addBreadcrumb).toHaveBeenCalledTimes(1); + expect(scope.addBreadcrumb).toHaveBeenCalledWith(breadcrumb.data); + }); +}); diff --git a/src/log/index.ts b/src/log/index.ts index cd3f2b4..a6c87c1 100644 --- a/src/log/index.ts +++ b/src/log/index.ts @@ -10,3 +10,5 @@ export type { export { createLogger } from './logger'; export { DetailedError, Breadcrumb } from './errors'; +export { createPinoHandler } from './handler/pino'; +export { createSentryHandler } from './handler/sentry';