@aircall/logger
Advanced tools
Comparing version 2.8.5 to 3.0.3
@@ -1,6 +0,59 @@ | ||
# Change Log | ||
# @aircall/logger | ||
All notable changes to this project will be documented in this file. | ||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. | ||
## 3.0.3 | ||
### Patch Changes | ||
- 63c3059: allow logger lib to be published to npm | ||
## 3.0.2 | ||
### Patch Changes | ||
- 3ae0677: Support QA env on bus | ||
## 3.0.1 | ||
### Patch Changes | ||
- ac67b6c: Stablize packages release | ||
## 3.0.0 | ||
### Major Changes | ||
- 2466248: migrate the logger module | ||
## 0.3.2 | ||
### Patch Changes | ||
- a7a8df5: migrate to typescript v5 | ||
## 0.3.1 | ||
### Patch Changes | ||
- 702089c: Bump typescript to v4.9 | ||
## 0.3.0 | ||
### Minor Changes | ||
- 7b0ab10: Fix minor bugs and prettify existing files | ||
## 0.2.0 | ||
### Minor Changes | ||
- 1c2d0fe: move to pnpm and adjust the dependencies to add all the missin ones | ||
## 0.1.0 | ||
### Minor Changes | ||
- c74b4e9: migrate the logger into hydra and rework the log-domains pkg | ||
All notable changes to this project will be documented in this file. | ||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. | ||
## [2.8.5](https://gitlab.com/aircall/shared/front-end-modules/compare/@aircall/logger@2.8.4...@aircall/logger@2.8.5) (2023-02-08) | ||
@@ -7,0 +60,0 @@ |
{ | ||
"name": "@aircall/logger", | ||
"version": "2.8.5", | ||
"main": "dist/index.js", | ||
"module": "dist/logger.esm.js", | ||
"types": "dist/index.d.ts", | ||
"version": "3.0.3", | ||
"description": "Aircall Next Logger Module", | ||
"main": "src/index.ts", | ||
"types": "src/index.ts", | ||
"sideEffects": false, | ||
"scripts": { | ||
"compile:schema:validation": "rm -rf src/validate-schema.js && ts-node scripts/validations/build-validate-schema.mjs", | ||
"prestart": "yarn compile:schema:validation", | ||
"prebuild": "yarn compile:schema:validation", | ||
"start": "npx tsdx watch", | ||
"clean": "rm -rf dist", | ||
"build": "npx tsdx build" | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"gitHead": "660ddb4e03853b2a948d08409fe9a1afb64f7472", | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "tsdx lint" | ||
} | ||
}, | ||
"size-limit": [ | ||
{ | ||
"path": "dist/logger.cjs.production.min.js", | ||
"limit": "24 KB" | ||
}, | ||
{ | ||
"path": "dist/logger.esm.js", | ||
"limit": "15 KB" | ||
} | ||
], | ||
"devDependencies": { | ||
"@aircall/eslint-config": "1.2.3", | ||
"@aircall/tsconfig": "1.2.1", | ||
"@size-limit/preset-small-lib": "8.1.0", | ||
"@types/jest": "29", | ||
"eslint": "8.30.0", | ||
"husky": "8.0.1", | ||
"size-limit": "8.1.0", | ||
"tsdx": "0.14.1", | ||
"tslib": "2.4.0" | ||
}, | ||
"dependencies": { | ||
"@datadog/browser-logs": "4.23.3", | ||
"ajv": "8.11.0", | ||
"ajv-formats": "2.1.1", | ||
"redux": "4.2.0" | ||
"@datadog/browser-logs": "4.17.1", | ||
"@datadog/browser-core": "4.24.0" | ||
}, | ||
"devDependencies": { | ||
"ts-node": "^10.9.1" | ||
"scripts": { | ||
"dev": "tsdx watch", | ||
"build": "tsdx build", | ||
"test": "tsdx test --passWithNoTests", | ||
"posttest": "pnpm run size", | ||
"lint": "eslint --ext ts src", | ||
"size": "size-limit" | ||
} | ||
} | ||
} |
@@ -18,3 +18,1 @@ global.console = { | ||
}; | ||
jest.mock('./src/validate-schema', () => jest.fn(), { virtual: true }); |
@@ -16,1 +16,14 @@ // Number of stored actions for the debug mode; | ||
export const DEFAULT_SENSITIVE_TEXT = '<sensitive>'; | ||
// Our common log schema relies on those custom keywords | ||
// @see https://ajv.js.org/strict-mode.html#json-schema-schemas | ||
export const CUSTOM_LOG_SCHEMA_KEYWORDS = [ | ||
'destination', | ||
'bytes_read', | ||
'bytes_written', | ||
'connectivity', | ||
'downlink_kbps', | ||
'signal_strength', | ||
'uplink_kbps', | ||
'useragent_details' | ||
]; |
@@ -1,3 +0,1 @@ | ||
export * from './actions'; | ||
export * from './middleware'; | ||
export * from './Logger'; |
@@ -1,32 +0,28 @@ | ||
jest.mock('@datadog/browser-logs'); | ||
import { datadogLogs, StatusType } from '@datadog/browser-logs'; | ||
import { Logger, LOGGER_ENVIRONMENT, LOGGER_LEVEL } from './Logger'; | ||
import { datadogLogs, StatusType } from '@datadog/browser-logs'; | ||
jest.mock('@datadog/browser-logs'); | ||
const properties = { foo: 'BAR' }; | ||
const [message, token] = ['MESSAGE', 'TOKEN']; | ||
const version = 'RELEASE'; | ||
const environment = LOGGER_ENVIRONMENT.TEST; | ||
const service = 'phone'; | ||
const user = { | ||
id: 0, | ||
company_id: 1 | ||
}; | ||
describe('Logger', (): void => { | ||
beforeEach((): void => { | ||
jest.spyOn(console, 'debug').mockImplementation((): void => undefined); | ||
jest.spyOn(console, 'info').mockImplementation((): void => undefined); | ||
jest.spyOn(console, 'warn').mockImplementation((): void => undefined); | ||
jest.spyOn(console, 'error').mockImplementation((): void => undefined); | ||
}); | ||
const user_session = { | ||
company_id: 0, | ||
device: 'DEVICE', | ||
environment, | ||
release: version, | ||
user_id: user.id, | ||
is_trial: true, | ||
tier_level: 'a', | ||
provider: 'Twilio' | ||
}; | ||
afterEach((): void => { | ||
jest.restoreAllMocks(); | ||
}); | ||
const logger = new Logger(); | ||
it('should be an instance of Logger', (): void => { | ||
const logger = new Logger({ | ||
token, | ||
level: LOGGER_LEVEL.debug | ||
}); | ||
describe('Logger', (): void => { | ||
it('should be an instance of Logger', (): void => { | ||
expect(logger).toBeInstanceOf(Logger); | ||
@@ -37,2 +33,6 @@ }); | ||
it('should queue events before initialization', (): void => { | ||
const logger = new Logger({ | ||
token, | ||
level: LOGGER_LEVEL.debug | ||
}); | ||
logger.info('FOO'); | ||
@@ -46,22 +46,12 @@ expect(logger.queue.length).toEqual(1); | ||
it('should set properties', (): void => { | ||
jest.spyOn(logger, 'setContext'); | ||
const context = { | ||
service, | ||
user_session | ||
}; | ||
logger.init({ | ||
context, | ||
const logger = new Logger({ | ||
token, | ||
level: LOGGER_LEVEL.debug, | ||
version, | ||
environment, | ||
service, | ||
user | ||
level: LOGGER_LEVEL.debug | ||
}); | ||
logger.init(); | ||
expect(logger.level).toEqual(LOGGER_LEVEL.debug); | ||
expect(logger.initialized).toEqual(true); | ||
expect(datadogLogs.init).toHaveBeenCalled(); | ||
expect(logger.setContext).toHaveBeenCalledWith(context); | ||
expect(datadogLogs.logger.setContext).toHaveBeenCalledWith(context); | ||
}); | ||
@@ -71,6 +61,16 @@ }); | ||
describe('log', (): void => { | ||
let logger: Logger; | ||
beforeEach((): void => { | ||
logger = new Logger({ | ||
token, | ||
level: LOGGER_LEVEL.debug | ||
}); | ||
logger.init(); | ||
}); | ||
it('should call logger.log', (): void => { | ||
jest.spyOn(datadogLogs.logger, 'log'); | ||
const logSpy = jest.spyOn(datadogLogs.logger, 'log'); | ||
logger.log(StatusType.info, message, properties); | ||
expect(datadogLogs.logger.log).toHaveBeenCalledWith(message, properties, StatusType.info); | ||
expect(logSpy).toHaveBeenCalledWith(message, properties, StatusType.info); | ||
}); | ||
@@ -86,2 +86,11 @@ | ||
describe('debug', (): void => { | ||
let logger: Logger; | ||
beforeEach((): void => { | ||
logger = new Logger({ | ||
token, | ||
level: LOGGER_LEVEL.debug | ||
}); | ||
logger.init(); | ||
}); | ||
it('should call logger.debug', (): void => { | ||
@@ -101,2 +110,11 @@ jest.spyOn(datadogLogs.logger, 'debug'); | ||
describe('info', (): void => { | ||
let logger: Logger; | ||
beforeEach((): void => { | ||
logger = new Logger({ | ||
token, | ||
level: LOGGER_LEVEL.debug | ||
}); | ||
logger.init(); | ||
}); | ||
it('should call logger.info', (): void => { | ||
@@ -116,2 +134,11 @@ jest.spyOn(datadogLogs.logger, 'info'); | ||
describe('warn', (): void => { | ||
let logger: Logger; | ||
beforeEach((): void => { | ||
logger = new Logger({ | ||
token, | ||
level: LOGGER_LEVEL.debug | ||
}); | ||
logger.init(); | ||
}); | ||
it('should call logger.warn', (): void => { | ||
@@ -131,2 +158,11 @@ jest.spyOn(datadogLogs.logger, 'warn'); | ||
describe('error', (): void => { | ||
let logger: Logger; | ||
beforeEach((): void => { | ||
logger = new Logger({ | ||
token, | ||
level: LOGGER_LEVEL.debug | ||
}); | ||
logger.init(); | ||
}); | ||
it('should call logger.error', (): void => { | ||
@@ -146,2 +182,11 @@ jest.spyOn(datadogLogs.logger, 'error'); | ||
describe('cleanProperties', (): void => { | ||
let logger: Logger; | ||
beforeEach((): void => { | ||
logger = new Logger({ | ||
token, | ||
level: LOGGER_LEVEL.debug | ||
}); | ||
logger.init(); | ||
}); | ||
it('return empty object if the properties are not defined', (): void => { | ||
@@ -207,35 +252,2 @@ expect(logger.cleanProperties()).toEqual({}); | ||
}); | ||
describe('beforeSendListener', (): void => { | ||
//@ts-ignore | ||
Date.now = jest.fn(() => new Date(2022, 7, 24, 8, 32, 16)); | ||
const logPayload = { | ||
date: 1660119130, | ||
foo: 'BAR', | ||
bar: 10, | ||
message: 'message', | ||
status: StatusType.info, | ||
view: { url: 'https://phone.aircall-staging.com/' } | ||
}; | ||
it('should add mandatory fields and validate schema', (): void => { | ||
logger.compiledLogSchema = jest.fn().mockReturnValue('test'); | ||
jest.spyOn(console, 'log'); | ||
const expected = { | ||
level: LOGGER_LEVEL.info, | ||
version, | ||
env: environment, | ||
host: '', | ||
service, | ||
timestamp: '2022-08-24T08:32:16.000Z', | ||
user, | ||
...logPayload | ||
}; | ||
logger.beforeSendListener(logPayload, version, environment, service, user); | ||
expect(logger.compiledLogSchema).toHaveBeenCalledWith(expected); | ||
expect(console.log).toBeCalledTimes(0); | ||
}); | ||
}); | ||
}); |
@@ -1,10 +0,12 @@ | ||
import { datadogLogs as sdk, StatusType, HandlerType, LogsEvent } from '@datadog/browser-logs'; | ||
import { Context, ConsoleApiName } from '@datadog/browser-core'; | ||
import { Context } from '@datadog/browser-core'; | ||
import { | ||
HandlerType, | ||
LogsInitConfiguration, | ||
datadogLogs as sdk, | ||
StatusType | ||
} from '@datadog/browser-logs'; | ||
import { SENSITIVE_KEYS, DEFAULT_SENSITIVE_TEXT } from './constants'; | ||
import { containsAValue, isString, deepMap, isObject, isArray } from './utils'; | ||
import { DEFAULT_SENSITIVE_TEXT, SENSITIVE_KEYS } from './constants'; | ||
import { containsAValue, deepMap, isArray, isObject, isString } from './utils'; | ||
// @ts-ignore | ||
import validate from './validate-schema'; | ||
export { StatusType as LOGGER_LEVEL }; | ||
@@ -21,64 +23,24 @@ | ||
export declare interface User extends Context { | ||
id?: number; | ||
company_id?: number; | ||
// cti_name?: string; | ||
// device: string; | ||
// electron_version?: string; | ||
// environment: LOGGER_ENVIRONMENT; | ||
// release: string; | ||
// is_trial?: boolean; | ||
// tier_level?: string; | ||
// provider?: string; | ||
export interface LoggerOptions { | ||
token: string; | ||
level: StatusType; | ||
debug?: boolean; | ||
} | ||
export declare interface UserSession extends Context { | ||
company_id?: number; | ||
cti_name?: string; | ||
device: string; | ||
electron_version?: string; | ||
environment: LOGGER_ENVIRONMENT; | ||
release: string; | ||
user_id?: number; | ||
is_trial?: boolean; | ||
tier_level?: string; | ||
provider?: string; | ||
export interface LoggerInitOptions { | ||
beforeSend: LogsInitConfiguration['beforeSend']; | ||
} | ||
export declare interface UserContext extends Context { | ||
service: string; | ||
user_session: UserSession; | ||
} | ||
export declare interface LoggerInitOptions { | ||
context: UserContext; | ||
token: string; | ||
level: StatusType; | ||
version: string; | ||
environment: LOGGER_ENVIRONMENT; | ||
service: string; | ||
user: User; | ||
forwardConsoleLogs?: ConsoleApiName[] | 'all'; | ||
} | ||
export class Logger { | ||
public level: StatusType; | ||
public level: StatusType | undefined; | ||
public initialized = false; | ||
public queue: Function[] = []; | ||
public queue: Array<() => void> = []; | ||
public logSchemaValidator: any; | ||
public compiledLogSchema: any; | ||
constructor(readonly options: LoggerOptions) {} | ||
// Init SDK with user informations, token and level | ||
public init({ | ||
level, | ||
context, | ||
token, | ||
version, | ||
environment, | ||
service, | ||
user, | ||
forwardConsoleLogs | ||
}: LoggerInitOptions): void { | ||
const isDevelopment: boolean = | ||
context.user_session.environment === LOGGER_ENVIRONMENT.DEVELOPMENT; | ||
this.compiledLogSchema = validate; | ||
public init(initOptions?: LoggerInitOptions): void { | ||
const { token, debug, level } = this.options; | ||
@@ -89,9 +51,8 @@ sdk.init({ | ||
forwardErrorsToLogs: true, | ||
forwardConsoleLogs: forwardConsoleLogs ?? ['error', 'warn'], // TODO PH-7453: do we want to forward warn logs as well? | ||
forwardConsoleLogs: ['error', 'warn'], // TODO PH-7453: do we want to forward warn logs as well? | ||
sampleRate: 100, | ||
beforeSend: log => this.beforeSendListener(log, version, environment, service, user) | ||
beforeSend: initOptions?.beforeSend | ||
}); | ||
this.setContext(context); | ||
sdk.logger.setHandler(isDevelopment ? HandlerType.console : HandlerType.http); | ||
sdk.logger.setHandler(debug ? HandlerType.console : HandlerType.http); | ||
@@ -103,70 +64,4 @@ this.setLevel(level); | ||
/** | ||
* Remove sensitive properties, add mandatory fields and validate the payload against the log schema. | ||
* | ||
* @param log | ||
* @param version | ||
* @param environment | ||
* @param service | ||
* @param user | ||
*/ | ||
public beforeSendListener( | ||
log: LogsEvent, | ||
version: string, | ||
environment: string, | ||
service: string, | ||
user: User | ||
): void { | ||
// TODO PH-7453: move the clean properties function here | ||
this.addMandatoryFields(log, version, environment, service, user); | ||
const valid = this.compiledLogSchema(log); | ||
if (!valid) { | ||
console.log( | ||
'An error occured while validating the log payload. For more information, please refer to distributed logging and tracing best practices documentation.', | ||
{ | ||
error: this.compiledLogSchema.errors, | ||
log | ||
} | ||
); | ||
} | ||
} | ||
/** | ||
* Every logs must include mandatory fields such as the environment or the version for instance. | ||
* This function adds all of them into the log payload. | ||
* | ||
* @param log | ||
* @param version | ||
* @param environment | ||
* @param service | ||
* @param user | ||
* @returns | ||
*/ | ||
private addMandatoryFields( | ||
log: LogsEvent, | ||
version: string, | ||
environment: string, | ||
service: string, | ||
user: User | ||
) { | ||
const currentDate = new Date(Date.now()); | ||
const datadogInternalContext = sdk.getInternalContext(); | ||
log.version = version; | ||
log.env = environment; | ||
log.service = service; | ||
log.host = datadogInternalContext?.session_id || ''; | ||
log.timestamp = currentDate.toISOString(); | ||
log.level = log.status; | ||
log.user = user; | ||
} | ||
// set logger context | ||
public setContext(context: UserContext) { | ||
sdk.logger.setContext(context); | ||
} | ||
// Send logs or enqueue them if the SDK isn't initialized | ||
private logOrEnqueue(fn: Function): void { | ||
private logOrEnqueue(fn: () => void): void { | ||
this.initialized ? fn() : this.queue.push(fn); | ||
@@ -173,0 +68,0 @@ } |
@@ -1,2 +0,2 @@ | ||
import { mapObject, map, deepMap, containsAValue } from './utils'; | ||
import { containsAValue, deepMap, map, mapObject } from './utils'; | ||
@@ -3,0 +3,0 @@ describe('utils', () => { |
{ | ||
"extends": "../../tsconfig.json", | ||
"extends": "@aircall/tsconfig/base.json", | ||
"compilerOptions": { | ||
"allowJs": true, | ||
"baseUrl": ".", | ||
"rootDir": "./src", | ||
"outDir": "./dist", | ||
"paths": { | ||
"@aircall/*": ["../../node_modules/@aircall/*/src"] | ||
} | ||
"target": "es2020", | ||
"rootDir": "./src" | ||
}, | ||
"include": ["**/*.ts"], | ||
"exclude": ["node_modules", "dist", "scripts", "**/*.spec.ts"] | ||
} | ||
"include": [ | ||
"**/*.ts" | ||
], | ||
"exclude": [ | ||
"dist", | ||
"node_modules" | ||
] | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
2
1
1
50745
9
11
1310
1
+ Added@datadog/browser-core@4.24.0
+ Added@datadog/browser-core@4.17.14.24.0(transitive)
+ Added@datadog/browser-logs@4.17.1(transitive)
- Removedajv@8.11.0
- Removedajv-formats@2.1.1
- Removedredux@4.2.0
- Removed@babel/runtime@7.26.0(transitive)
- Removed@datadog/browser-core@4.23.3(transitive)
- Removed@datadog/browser-logs@4.23.3(transitive)
- Removedajv@8.11.0(transitive)
- Removedajv-formats@2.1.1(transitive)
- Removedfast-deep-equal@3.1.3(transitive)
- Removedjson-schema-traverse@1.0.0(transitive)
- Removedpunycode@2.3.1(transitive)
- Removedredux@4.2.0(transitive)
- Removedregenerator-runtime@0.14.1(transitive)
- Removedrequire-from-string@2.0.2(transitive)
- Removeduri-js@4.4.1(transitive)
Updated@datadog/browser-logs@4.17.1