@codeleap/logger 5.0.11 → 5.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -6
- package/package.json.bak +1 -1
- package/src/index.ts +2 -5
- package/src/lib/Logger.ts +72 -0
- package/src/lib/Sentry.ts +62 -0
- package/src/{Slack.ts → lib/Slack.ts} +17 -13
- package/src/lib/index.ts +1 -0
- package/src/{performance → lib/performance}/errors.ts +2 -2
- package/src/lib/performance/index.ts +79 -0
- package/src/lib/performance/types.ts +6 -0
- package/src/types.ts +34 -41
- package/src/Analytics.ts +0 -67
- package/src/Logger.ts +0 -223
- package/src/Sentry.ts +0 -54
- package/src/constants.ts +0 -37
- package/src/obfuscate.ts +0 -76
- package/src/performance/index.ts +0 -86
- package/src/silentLogger.ts +0 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codeleap/logger",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.12",
|
|
4
4
|
"main": "src/index.ts",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"directory": "packages/logger"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@codeleap/types": "5.0.
|
|
13
|
-
"@codeleap/utils": "5.0.
|
|
14
|
-
"@codeleap/config": "5.0.
|
|
12
|
+
"@codeleap/types": "5.0.12",
|
|
13
|
+
"@codeleap/utils": "5.0.12",
|
|
14
|
+
"@codeleap/config": "5.0.12",
|
|
15
15
|
"ts-node-dev": "1.1.8",
|
|
16
16
|
"@sentry/types": "8.40.0"
|
|
17
17
|
},
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"build": "echo 'No build needed'"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
|
-
"@codeleap/types": "5.0.
|
|
23
|
-
"@codeleap/utils": "5.0.
|
|
22
|
+
"@codeleap/types": "5.0.12",
|
|
23
|
+
"@codeleap/utils": "5.0.12",
|
|
24
24
|
"typescript": "5.5.2",
|
|
25
25
|
"react": "18.2.0"
|
|
26
26
|
},
|
package/package.json.bak
CHANGED
package/src/index.ts
CHANGED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { LoggerConfig } from '../types'
|
|
2
|
+
import { SentryService } from './Sentry'
|
|
3
|
+
import { SlackService } from './Slack'
|
|
4
|
+
import { PerformanceService } from './performance'
|
|
5
|
+
|
|
6
|
+
export class Logger {
|
|
7
|
+
static initialized = false
|
|
8
|
+
|
|
9
|
+
private config: LoggerConfig
|
|
10
|
+
|
|
11
|
+
slack: SlackService
|
|
12
|
+
|
|
13
|
+
sentry: SentryService
|
|
14
|
+
|
|
15
|
+
perf: PerformanceService
|
|
16
|
+
|
|
17
|
+
private overrideConsoleMethod(args: unknown[], originalConsole: Console['log']) {
|
|
18
|
+
if (!Logger.initialized) return
|
|
19
|
+
|
|
20
|
+
const ignoreLogs = this.config.Logger.ignoreLogs
|
|
21
|
+
const shouldIgnore = typeof args[0] === 'string' && ignoreLogs.some(ignoredWarning => args.join(' ').includes(ignoredWarning))
|
|
22
|
+
|
|
23
|
+
if (shouldIgnore) return
|
|
24
|
+
|
|
25
|
+
return originalConsole.apply(console, args)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
const consoles = ['log', 'warn', 'error']
|
|
30
|
+
|
|
31
|
+
consoles.forEach(level => {
|
|
32
|
+
const consoleRef = console[level]
|
|
33
|
+
console[level] = (...args: unknown[]) => this.overrideConsoleMethod(args, consoleRef)
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
initialize<T extends LoggerConfig>(config: T) {
|
|
38
|
+
if (Logger.initialized) return
|
|
39
|
+
|
|
40
|
+
this.config = config
|
|
41
|
+
|
|
42
|
+
this.sentry = new SentryService(config)
|
|
43
|
+
|
|
44
|
+
this.slack = new SlackService(config)
|
|
45
|
+
|
|
46
|
+
this.perf = new PerformanceService(config)
|
|
47
|
+
|
|
48
|
+
Logger.initialized = true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
info(...args: unknown[]) {
|
|
52
|
+
throw new Error('Logger: implement the method "info"')
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
error(...args: unknown[]) {
|
|
56
|
+
throw new Error('Logger: implement the method "error"')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
warn(...args: unknown[]) {
|
|
60
|
+
throw new Error('Logger: implement the method "warn"')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
log(...args: unknown[]) {
|
|
64
|
+
throw new Error('Logger: implement the method "log"')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
debug(...args: unknown[]) {
|
|
68
|
+
throw new Error('Logger: implement the method "debug"')
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const logger = new Logger()
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { Breadcrumb, ClientOptions, SeverityLevel, Client } from '@sentry/types'
|
|
2
|
+
import { LoggerConfig } from '../types'
|
|
3
|
+
|
|
4
|
+
const SentrySeverityMap: Record<string, SeverityLevel> = {
|
|
5
|
+
debug: 'debug',
|
|
6
|
+
error: 'error',
|
|
7
|
+
info: 'info',
|
|
8
|
+
log: 'log',
|
|
9
|
+
warn: 'warning',
|
|
10
|
+
silent: 'log',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type SentryProvider = {
|
|
14
|
+
addBreadcrumb: (args: Breadcrumb) => void
|
|
15
|
+
init(options: ClientOptions): Client
|
|
16
|
+
captureException(err: any): void
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class SentryService {
|
|
20
|
+
get provider(): SentryProvider {
|
|
21
|
+
return this.config.Sentry.provider
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
private get enabled() {
|
|
25
|
+
return this.config.Sentry.enabled
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
constructor(private config: LoggerConfig) {
|
|
29
|
+
if (config.Sentry.enabled) {
|
|
30
|
+
const initOptions: ClientOptions = {
|
|
31
|
+
dsn: config.Sentry.dsn,
|
|
32
|
+
debug: config.Sentry.debug,
|
|
33
|
+
beforeBreadcrumb: config.Sentry.beforeBreadcrumb,
|
|
34
|
+
integrations: [],
|
|
35
|
+
enabled: this.enabled,
|
|
36
|
+
...config.Sentry.initArgs,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
this.provider?.init?.(initOptions)
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
captureBreadcrumb(type: string, msg: string, data: any, category = `logger:${type}`) {
|
|
44
|
+
if (!this.enabled) return
|
|
45
|
+
|
|
46
|
+
const sentryArgs: Breadcrumb = {
|
|
47
|
+
message: msg,
|
|
48
|
+
data,
|
|
49
|
+
category,
|
|
50
|
+
level: SentrySeverityMap[type],
|
|
51
|
+
type: '',
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.provider.addBreadcrumb(sentryArgs)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
captureException(err: any) {
|
|
58
|
+
if (!this.enabled) return
|
|
59
|
+
|
|
60
|
+
this.provider.captureException(err)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { inspect } from 'util'
|
|
2
|
-
import { TypeGuards
|
|
3
|
-
|
|
4
|
-
type EchoSlackConfig = AppSettings['Slack']['echo']
|
|
2
|
+
import { TypeGuards } from '@codeleap/types'
|
|
3
|
+
import { LoggerConfig } from '../types'
|
|
5
4
|
|
|
6
5
|
type EchoSlack = {
|
|
7
6
|
label: string
|
|
@@ -20,21 +19,26 @@ type EchoSlackOptions = {
|
|
|
20
19
|
}
|
|
21
20
|
|
|
22
21
|
const DEFAULT_CHANNEL = '#_dev_logs'
|
|
22
|
+
|
|
23
23
|
const DEFAULT_BASE_URL = 'https://slack.com/api/chat.postMessage'
|
|
24
24
|
|
|
25
25
|
export class SlackService {
|
|
26
|
-
private echoConfig:
|
|
26
|
+
private echoConfig: LoggerConfig['Slack']['echo']
|
|
27
27
|
|
|
28
|
-
private isDev:
|
|
28
|
+
private isDev: LoggerConfig['Environment']['IsDev']
|
|
29
29
|
|
|
30
|
-
private appName:
|
|
30
|
+
private appName: LoggerConfig['AppName']
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
private api
|
|
33
33
|
|
|
34
|
-
constructor(
|
|
35
|
-
this.echoConfig =
|
|
36
|
-
this.isDev =
|
|
37
|
-
this.appName =
|
|
34
|
+
constructor(private config: LoggerConfig) {
|
|
35
|
+
this.echoConfig = config.Slack.echo
|
|
36
|
+
this.isDev = config.Environment.IsDev
|
|
37
|
+
this.appName = config.AppName
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
setApi(fetcher: any) {
|
|
41
|
+
this.api = fetcher
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
async echo(
|
|
@@ -55,7 +59,7 @@ export class SlackService {
|
|
|
55
59
|
try {
|
|
56
60
|
const data = {
|
|
57
61
|
'channel': this?.echoConfig?.channel ?? DEFAULT_CHANNEL,
|
|
58
|
-
text: slack,
|
|
62
|
+
'text': slack,
|
|
59
63
|
'username': `${this.appName} Log`,
|
|
60
64
|
'icon_url': this?.echoConfig?.icon,
|
|
61
65
|
...settingsData,
|
|
@@ -135,4 +139,4 @@ export class SlackService {
|
|
|
135
139
|
|
|
136
140
|
return slack
|
|
137
141
|
}
|
|
138
|
-
}
|
|
142
|
+
}
|
package/src/lib/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Logger'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { InspectRenderOptions } from '
|
|
1
|
+
import { InspectRenderOptions } from './types'
|
|
2
2
|
|
|
3
3
|
type ErrorArgs = InspectRenderOptions & {
|
|
4
4
|
name: string
|
|
@@ -23,4 +23,4 @@ export class PerformanceError extends Error {
|
|
|
23
23
|
super(defineError(errorName, args))
|
|
24
24
|
this.name = 'Codeleap:Perf'
|
|
25
25
|
}
|
|
26
|
-
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { throttle } from '@codeleap/utils'
|
|
2
|
+
import { useEffect } from 'react'
|
|
3
|
+
import { PerformanceError } from './errors'
|
|
4
|
+
import { InspectRenderOptions } from './types'
|
|
5
|
+
import { LoggerConfig } from '../../types'
|
|
6
|
+
|
|
7
|
+
export * from './types'
|
|
8
|
+
|
|
9
|
+
export class PerformanceService {
|
|
10
|
+
renderCounter: Record<string, number> = {}
|
|
11
|
+
|
|
12
|
+
constructor(private config: LoggerConfig) { }
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* inspectRender monitors how much time a component render per second.
|
|
16
|
+
* Use logger.perf.inspectRender('ComponentName') inside a component to monitor it.
|
|
17
|
+
* @param {string} name - Component name
|
|
18
|
+
* @param {PerformanceInspector} options - Some options for the inspector
|
|
19
|
+
* @returns
|
|
20
|
+
*/
|
|
21
|
+
inspectRender = (
|
|
22
|
+
name: string,
|
|
23
|
+
options: InspectRenderOptions = {
|
|
24
|
+
noHooks: false,
|
|
25
|
+
logMode: 'summarized',
|
|
26
|
+
throttleInterval: 1000,
|
|
27
|
+
},
|
|
28
|
+
) => {
|
|
29
|
+
const config = this.config.Logger.performanceInspector
|
|
30
|
+
|
|
31
|
+
const blacklist = config.blacklist || []
|
|
32
|
+
|
|
33
|
+
if (blacklist.some((item) => name.startsWith(item))) return
|
|
34
|
+
|
|
35
|
+
const { noHooks, logMode, throttleInterval, maxRenders = config.maxRenders } = options
|
|
36
|
+
|
|
37
|
+
if (!config.enabled || !this.config.Environment.IsDev) {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!noHooks) {
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
console.log(`[PerformanceInspector] Mounted -> ${name}`)
|
|
44
|
+
|
|
45
|
+
return () => {
|
|
46
|
+
console.log(`[PerformanceInspector] Unmounted -> ${name}`)
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.renderCounter[name] = this.renderCounter[name] ? this.renderCounter[name] + 1 : 1
|
|
52
|
+
|
|
53
|
+
const renders = this.renderCounter[name]
|
|
54
|
+
|
|
55
|
+
if (renders > maxRenders) {
|
|
56
|
+
this.renderCounter[name] = 0
|
|
57
|
+
|
|
58
|
+
throw new PerformanceError('maxRenders', {
|
|
59
|
+
name,
|
|
60
|
+
throttleInterval,
|
|
61
|
+
maxRenders,
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (logMode === 'raw') {
|
|
66
|
+
console.log(`[PerformanceInspector] Rendered -> ${name}: ${renders}`)
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function logSummary() {
|
|
71
|
+
if (renders <= 0) return
|
|
72
|
+
|
|
73
|
+
console.log(`[PerformanceInspector] Render summary -> ${name}: ${renders}`)
|
|
74
|
+
this.renderCounter[name] = 0
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
throttle(logSummary, name, throttleInterval)
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -1,45 +1,38 @@
|
|
|
1
|
-
import { FunctionType } from '@codeleap/types'
|
|
2
|
-
import { colors, foregroundColors } from './constants'
|
|
3
1
|
|
|
4
|
-
|
|
2
|
+
export type LoggerConfig = {
|
|
3
|
+
AppName: string
|
|
4
|
+
|
|
5
|
+
Environment: {
|
|
6
|
+
IsDev: boolean
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
Slack: {
|
|
10
|
+
echo: {
|
|
11
|
+
channel?: string
|
|
12
|
+
icon: string
|
|
13
|
+
token: string
|
|
14
|
+
baseURL?: string
|
|
15
|
+
enabled?: boolean
|
|
16
|
+
options?: Record<string, any>
|
|
17
|
+
}
|
|
18
|
+
}
|
|
5
19
|
|
|
6
|
-
|
|
20
|
+
Logger: {
|
|
21
|
+
ignoreLogs: string[]
|
|
7
22
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
export type DebugColors = {
|
|
15
|
-
[Property in keyof typeof foregroundColors as `${Lowercase<
|
|
16
|
-
string & Property
|
|
17
|
-
>}`]: (...args: LogFunctionArgs) => void;
|
|
18
|
-
}
|
|
19
|
-
export type DebugColor = keyof DebugColors
|
|
20
|
-
export type LogToTerminalArgs = {
|
|
21
|
-
logType: LogType
|
|
22
|
-
args: LogFunctionArgs
|
|
23
|
-
color?: keyof DebugColors
|
|
24
|
-
deviceIdentifier?: string
|
|
25
|
-
stringify?: boolean
|
|
26
|
-
logKeys?: boolean
|
|
27
|
-
}
|
|
28
|
-
export type LogToTerminal = FunctionType<[LogToTerminalArgs], void>
|
|
23
|
+
performanceInspector: {
|
|
24
|
+
enabled: boolean
|
|
25
|
+
maxRenders: number
|
|
26
|
+
blacklist: string[]
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export type SentryProvider = {
|
|
40
|
-
addBreadcrumb: FunctionType<[Breadcrumb], void>
|
|
41
|
-
init(options: ClientOptions): Client
|
|
42
|
-
captureException(err: any): void
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export type LoggerMiddleware = FunctionType<[arguments: LogToTerminalArgs, formattedContent: string[]], any>
|
|
30
|
+
Sentry: {
|
|
31
|
+
enabled: boolean
|
|
32
|
+
dsn: string
|
|
33
|
+
provider: any
|
|
34
|
+
debug?: boolean
|
|
35
|
+
initArgs?: any
|
|
36
|
+
beforeBreadcrumb?: any
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/Analytics.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import { obfuscate } from './obfuscate'
|
|
2
|
-
import { FunctionType, AnyFunction, AppSettings } from '@codeleap/types'
|
|
3
|
-
|
|
4
|
-
export type AnalyticsObject = {
|
|
5
|
-
name: string
|
|
6
|
-
type: 'interaction' | 'event'
|
|
7
|
-
data: any
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
type IAnalyticsArgs = {
|
|
11
|
-
init(): any
|
|
12
|
-
prepareData: () => any
|
|
13
|
-
error?: (err: any) => any
|
|
14
|
-
} & Record<`on${Capitalize<AnalyticsObject['type']>}`, FunctionType<[AnalyticsObject], void>>
|
|
15
|
-
|
|
16
|
-
export class Analytics {
|
|
17
|
-
|
|
18
|
-
constructor(private callers: IAnalyticsArgs, private settings: AppSettings) {
|
|
19
|
-
this.callers.init()
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
private prepare() {
|
|
24
|
-
const data = this.callers.prepareData()
|
|
25
|
-
|
|
26
|
-
return data
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
obfuscate(data) {
|
|
30
|
-
return obfuscate({
|
|
31
|
-
object: data,
|
|
32
|
-
keys: this?.settings?.Logger?.Obfuscate?.keys || [],
|
|
33
|
-
values: this?.settings?.Logger?.Obfuscate?.values || [],
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
event(name: string, data = {}) {
|
|
38
|
-
this.handle(name, data, 'event', this.callers.onEvent)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interaction(name: string, data = {}) {
|
|
42
|
-
this.handle(name, data, 'interaction', this.callers.onInteraction)
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
onError(cb) {
|
|
47
|
-
this.callers.error = cb
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
private handle(name: string, data: any, type: AnalyticsObject['type'], fn: AnyFunction) {
|
|
51
|
-
try {
|
|
52
|
-
|
|
53
|
-
const obfuscated = this.obfuscate({
|
|
54
|
-
...data,
|
|
55
|
-
...this.prepare(),
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
fn({
|
|
59
|
-
name,
|
|
60
|
-
type,
|
|
61
|
-
data: obfuscated,
|
|
62
|
-
})
|
|
63
|
-
} catch (e) {
|
|
64
|
-
this.callers.error(e)
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
package/src/Logger.ts
DELETED
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { inspect } from 'util'
|
|
2
|
-
import { TypeGuards, LogType, AppSettings } from '@codeleap/types'
|
|
3
|
-
import { Analytics } from './Analytics'
|
|
4
|
-
import { SentryService } from './Sentry'
|
|
5
|
-
import { SlackService } from './Slack'
|
|
6
|
-
import { LogToTerminal, LogFunctionArgs, LogToTerminalArgs, LoggerMiddleware } from './types'
|
|
7
|
-
|
|
8
|
-
const logLevels: LogType[] = ['debug', 'info', 'log', 'warn', 'error']
|
|
9
|
-
|
|
10
|
-
const emptyFunction = () => { }
|
|
11
|
-
|
|
12
|
-
const hollowAnalytics = new Analytics({
|
|
13
|
-
init: emptyFunction,
|
|
14
|
-
onEvent: emptyFunction,
|
|
15
|
-
onInteraction: emptyFunction,
|
|
16
|
-
prepareData: () => ({}),
|
|
17
|
-
}, {})
|
|
18
|
-
|
|
19
|
-
export class Logger {
|
|
20
|
-
static settings: AppSettings
|
|
21
|
-
|
|
22
|
-
settings: AppSettings
|
|
23
|
-
|
|
24
|
-
sentry: SentryService
|
|
25
|
-
|
|
26
|
-
slack: SlackService
|
|
27
|
-
|
|
28
|
-
middleware: LoggerMiddleware[] = []
|
|
29
|
-
|
|
30
|
-
constructor(settings: AppSettings, middleware?: LoggerMiddleware[], public analytics?: Analytics) {
|
|
31
|
-
this.settings = settings
|
|
32
|
-
this.middleware = middleware || []
|
|
33
|
-
if (settings.Logger.isMain) {
|
|
34
|
-
Logger.settings = settings
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (settings?.Logger?.IgnoreWarnings?.length) {
|
|
38
|
-
const newConsole = (args, oldConsole) => {
|
|
39
|
-
const shouldIgnore = typeof args[0] === 'string' &&
|
|
40
|
-
settings.Logger.IgnoreWarnings.some(ignoredWarning => args.join(' ').includes(ignoredWarning))
|
|
41
|
-
if (shouldIgnore) return
|
|
42
|
-
else return oldConsole.apply(console, args)
|
|
43
|
-
}
|
|
44
|
-
const consoles = ['log', 'warn', 'error']
|
|
45
|
-
|
|
46
|
-
consoles.forEach(t => {
|
|
47
|
-
const tmp = console[t]
|
|
48
|
-
console[t] = (...args) => newConsole(args, tmp)
|
|
49
|
-
})
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
this.sentry = new SentryService(settings)
|
|
53
|
-
|
|
54
|
-
this.slack = new SlackService(settings)
|
|
55
|
-
|
|
56
|
-
if (!analytics) {
|
|
57
|
-
this.analytics = hollowAnalytics
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
this.analytics.onError((err) => {
|
|
61
|
-
this.logToTerminal({
|
|
62
|
-
logType: 'error',
|
|
63
|
-
args: ['Error on analytics event', err, 'Internal'],
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
static formatContent(logArgs: LogToTerminalArgs) {
|
|
70
|
-
const { logType, args: content, deviceIdentifier: deviceId, stringify, logKeys = true } = logArgs
|
|
71
|
-
|
|
72
|
-
const [descriptionOrValue, value, category] = content
|
|
73
|
-
|
|
74
|
-
const nArgs = content.length
|
|
75
|
-
let logContent = content
|
|
76
|
-
|
|
77
|
-
const logValue = nArgs === 1 ? descriptionOrValue : value
|
|
78
|
-
|
|
79
|
-
const shouldStringify = stringify && !!logValue && TypeGuards.isObject(logValue) && !(logValue instanceof Error)
|
|
80
|
-
const inspectOptions = Logger?.settings?.Logger?.inspect || {}
|
|
81
|
-
|
|
82
|
-
const displayValue = shouldStringify ? inspect(logValue, {
|
|
83
|
-
depth: 5,
|
|
84
|
-
showHidden: true,
|
|
85
|
-
...inspectOptions,
|
|
86
|
-
}) : logValue
|
|
87
|
-
|
|
88
|
-
if (nArgs === 3) {
|
|
89
|
-
logContent = [
|
|
90
|
-
`(${category}) ${descriptionOrValue}${displayValue ? ' ->' : ''}`,
|
|
91
|
-
displayValue,
|
|
92
|
-
]
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (nArgs === 2) {
|
|
96
|
-
logContent = [
|
|
97
|
-
`${descriptionOrValue}${displayValue ? ' ->' : ''}`,
|
|
98
|
-
displayValue,
|
|
99
|
-
]
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (nArgs === 1) {
|
|
103
|
-
const isObj = typeof descriptionOrValue === 'object' && !(descriptionOrValue instanceof Error)
|
|
104
|
-
const keys = isObj ? Object.keys(descriptionOrValue) : null
|
|
105
|
-
const title = isObj && keys.length && logKeys ?
|
|
106
|
-
`${keys.filter(i => !!i).slice(0, 3).join(', ')}${keys.length > 3 ? '...' : ''} ->`
|
|
107
|
-
: null
|
|
108
|
-
|
|
109
|
-
if (title) {
|
|
110
|
-
logContent = [
|
|
111
|
-
title,
|
|
112
|
-
displayValue,
|
|
113
|
-
]
|
|
114
|
-
} else {
|
|
115
|
-
logContent = [
|
|
116
|
-
displayValue,
|
|
117
|
-
]
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return logContent
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
static coloredLog: LogToTerminal = (logArgs) => {
|
|
125
|
-
const { logType, args: content, deviceIdentifier: deviceId, stringify } = logArgs
|
|
126
|
-
|
|
127
|
-
const logContent = Logger.formatContent(logArgs)
|
|
128
|
-
|
|
129
|
-
const displayLog = logType === 'error' ? 'warn' : logType
|
|
130
|
-
|
|
131
|
-
console[displayLog](deviceId, ...logContent)
|
|
132
|
-
|
|
133
|
-
return logContent
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
private logToTerminal: LogToTerminal = (logArgs) => {
|
|
137
|
-
const { logType, args, color } = logArgs
|
|
138
|
-
|
|
139
|
-
if (this.settings.Logger.Level === 'silent') return
|
|
140
|
-
|
|
141
|
-
const shouldLog = TypeGuards.isString(this.settings.Logger.Level) ?
|
|
142
|
-
logLevels.indexOf(logType) >=
|
|
143
|
-
logLevels.indexOf(this.settings.Logger.Level) : this.settings.Logger.Level.includes(logType)
|
|
144
|
-
if (!shouldLog) return
|
|
145
|
-
|
|
146
|
-
const content = Logger.formatContent(logArgs)
|
|
147
|
-
|
|
148
|
-
if (this.settings.Environment.IsDev) {
|
|
149
|
-
|
|
150
|
-
const deviceId = this.settings.Logger?.DeviceIdentifier ?
|
|
151
|
-
`[${this.settings.Logger.DeviceIdentifier}]` : ''
|
|
152
|
-
|
|
153
|
-
const stringify = this.settings.Logger?.StringifyObjects
|
|
154
|
-
|
|
155
|
-
this.middleware.forEach(m => m(logArgs, content))
|
|
156
|
-
|
|
157
|
-
Logger.coloredLog(
|
|
158
|
-
{
|
|
159
|
-
logType: logType as LogType,
|
|
160
|
-
args,
|
|
161
|
-
color,
|
|
162
|
-
deviceIdentifier: deviceId,
|
|
163
|
-
stringify,
|
|
164
|
-
},
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (!this.settings.Environment.IsDev || this.settings.Logger.alwaysSendToSentry) {
|
|
170
|
-
try {
|
|
171
|
-
|
|
172
|
-
this.middleware.forEach(m => m(logArgs, content))
|
|
173
|
-
if (['info', 'log'].includes(logType)) {
|
|
174
|
-
|
|
175
|
-
this.sentry.captureBreadcrumb(
|
|
176
|
-
logType,
|
|
177
|
-
content,
|
|
178
|
-
)
|
|
179
|
-
}
|
|
180
|
-
if (['error'].includes(logType)) {
|
|
181
|
-
this.sentry.sendLog(args?.[1] || args?.[0])
|
|
182
|
-
}
|
|
183
|
-
} catch (e) {
|
|
184
|
-
// Nothing
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
info(...args: LogFunctionArgs) {
|
|
190
|
-
this.logToTerminal({
|
|
191
|
-
args,
|
|
192
|
-
logType: 'info',
|
|
193
|
-
})
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
error(...args: LogFunctionArgs) {
|
|
197
|
-
this.logToTerminal({
|
|
198
|
-
args,
|
|
199
|
-
logType: 'error',
|
|
200
|
-
})
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
warn(...args: LogFunctionArgs) {
|
|
204
|
-
this.logToTerminal({
|
|
205
|
-
args,
|
|
206
|
-
logType: 'warn',
|
|
207
|
-
})
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
log(...args: LogFunctionArgs) {
|
|
211
|
-
this.logToTerminal({
|
|
212
|
-
args,
|
|
213
|
-
logType: 'log',
|
|
214
|
-
})
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
debug(...args: LogFunctionArgs) {
|
|
218
|
-
this.logToTerminal({
|
|
219
|
-
args,
|
|
220
|
-
logType: 'debug',
|
|
221
|
-
})
|
|
222
|
-
}
|
|
223
|
-
}
|
package/src/Sentry.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import type { Breadcrumb, ClientOptions } from '@sentry/types'
|
|
2
|
-
import { AppSettings } from '@codeleap/types'
|
|
3
|
-
import {
|
|
4
|
-
LogFunctionArgs,
|
|
5
|
-
LogType,
|
|
6
|
-
SentrySeverityMap,
|
|
7
|
-
SentryProvider,
|
|
8
|
-
} from './types'
|
|
9
|
-
|
|
10
|
-
export class SentryService {
|
|
11
|
-
private sentry: SentryProvider
|
|
12
|
-
|
|
13
|
-
private use: boolean
|
|
14
|
-
|
|
15
|
-
constructor(settings: AppSettings) {
|
|
16
|
-
this.use = settings?.Sentry?.enable
|
|
17
|
-
this.sentry = settings?.Sentry?.provider as SentryProvider
|
|
18
|
-
if (this.use) {
|
|
19
|
-
const isDebug = settings?.Sentry?.debug || false
|
|
20
|
-
if (isDebug) console.log('> > > Initializing Sentry', settings.Sentry)
|
|
21
|
-
const initObj:ClientOptions = {
|
|
22
|
-
dsn: settings.Sentry.dsn,
|
|
23
|
-
debug: isDebug,
|
|
24
|
-
integrations: [],
|
|
25
|
-
...settings?.Sentry?.initArgs,
|
|
26
|
-
}
|
|
27
|
-
if (settings?.Sentry?.beforeBreadcrumb) {
|
|
28
|
-
initObj.beforeBreadcrumb = settings?.Sentry?.beforeBreadcrumb
|
|
29
|
-
}
|
|
30
|
-
this.sentry?.init?.(initObj)
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
captureBreadcrumb(type: LogType, content: LogFunctionArgs) {
|
|
35
|
-
if (!this.use) return
|
|
36
|
-
|
|
37
|
-
const [message, data, category] = content
|
|
38
|
-
|
|
39
|
-
const sentryArgs: Breadcrumb = {
|
|
40
|
-
message,
|
|
41
|
-
data,
|
|
42
|
-
category,
|
|
43
|
-
level: SentrySeverityMap[type],
|
|
44
|
-
type: '',
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
this.sentry.addBreadcrumb(sentryArgs)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
sendLog(err?: any) {
|
|
51
|
-
if (!this.use) return
|
|
52
|
-
this.sentry.captureException(err)
|
|
53
|
-
}
|
|
54
|
-
}
|
package/src/constants.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { ConsoleColor } from './types'
|
|
2
|
-
import { LogType } from '@codeleap/types'
|
|
3
|
-
|
|
4
|
-
export const foregroundColors = {
|
|
5
|
-
Black: '\x1b[30m',
|
|
6
|
-
Red: '\x1b[31m',
|
|
7
|
-
Green: '\x1b[32m',
|
|
8
|
-
Yellow: '\x1b[33m',
|
|
9
|
-
Blue: '\x1b[34m',
|
|
10
|
-
Magenta: '\x1b[35m',
|
|
11
|
-
Cyan: '\x1b[36m',
|
|
12
|
-
White: '\x1b[37m',
|
|
13
|
-
} as const
|
|
14
|
-
|
|
15
|
-
export const formatColors = {
|
|
16
|
-
Reset: '\x1b[0m',
|
|
17
|
-
Bright: '\x1b[1m',
|
|
18
|
-
Dim: '\x1b[2m',
|
|
19
|
-
Underscore: '\x1b[4m',
|
|
20
|
-
Blink: '\x1b[5m',
|
|
21
|
-
Reverse: '\x1b[7m',
|
|
22
|
-
Hidden: '\x1b[8m',
|
|
23
|
-
} as const
|
|
24
|
-
|
|
25
|
-
export const colors = {
|
|
26
|
-
...foregroundColors,
|
|
27
|
-
...formatColors,
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export const logColors: Record<LogType, ConsoleColor> = {
|
|
31
|
-
error: 'Red',
|
|
32
|
-
info: 'White',
|
|
33
|
-
warn: 'Yellow',
|
|
34
|
-
debug: 'Magenta',
|
|
35
|
-
log: 'White',
|
|
36
|
-
silent: 'Green',
|
|
37
|
-
}
|
package/src/obfuscate.ts
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { cloneDeep } from '@codeleap/utils'
|
|
2
|
-
import { Matcher } from '@codeleap/types'
|
|
3
|
-
import { inspect } from 'util'
|
|
4
|
-
import parse from 'url-parse'
|
|
5
|
-
|
|
6
|
-
type ObfuscateArgs = {
|
|
7
|
-
object: any
|
|
8
|
-
keys: (Matcher<'key'>)[]
|
|
9
|
-
values: (Matcher<'value'>)[]
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function removeKey(obj, key) {
|
|
13
|
-
if (obj?.hasOwnProperty(key)) {
|
|
14
|
-
obj[key] = '[secret]'
|
|
15
|
-
}
|
|
16
|
-
for (const subObj in obj) {
|
|
17
|
-
if (typeof obj[subObj] == 'object') {
|
|
18
|
-
removeKey(obj[subObj], key)
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function removeValue(obj, value) {
|
|
24
|
-
for (const subObj in obj) {
|
|
25
|
-
const isString = typeof obj[subObj] == 'string'
|
|
26
|
-
if (isString) {
|
|
27
|
-
const isRegex = value instanceof RegExp
|
|
28
|
-
const match = isRegex ? value.test(obj[subObj]) : obj[subObj].includes(value)
|
|
29
|
-
if (match) {
|
|
30
|
-
if (obj[subObj].startsWith('http')) {
|
|
31
|
-
const url = parse(obj[subObj])
|
|
32
|
-
obj[subObj] = `${url.origin}${url.pathname}/[secret]`
|
|
33
|
-
} else {
|
|
34
|
-
obj[subObj] = '[secret]'
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
if (typeof obj[subObj] == 'object') {
|
|
39
|
-
removeValue(obj[subObj], value)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function obfuscate(args: ObfuscateArgs) {
|
|
45
|
-
const { object, keys, values } = args
|
|
46
|
-
|
|
47
|
-
let isCircular = false
|
|
48
|
-
try {
|
|
49
|
-
JSON.stringify(args)
|
|
50
|
-
} catch (e) {
|
|
51
|
-
isCircular = true
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (typeof object === 'object' && !isCircular) {
|
|
55
|
-
let cleanData = {}
|
|
56
|
-
try {
|
|
57
|
-
cleanData = cloneDeep(object)
|
|
58
|
-
keys.forEach(fieldName => removeKey(cleanData, fieldName))
|
|
59
|
-
values.forEach(fieldName => removeValue(cleanData, fieldName))
|
|
60
|
-
} catch (err1) {
|
|
61
|
-
try {
|
|
62
|
-
cleanData = inspect(object, { depth: 1 })
|
|
63
|
-
} catch (err2) {
|
|
64
|
-
cleanData = { value: `Couldn't process data` }
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
const result = cleanData
|
|
68
|
-
return result
|
|
69
|
-
} else {
|
|
70
|
-
if (isCircular) {
|
|
71
|
-
return { ...args.object, WARNING: 'Circular reference detected' }
|
|
72
|
-
} else {
|
|
73
|
-
return args.object
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
package/src/performance/index.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { throttle } from '@codeleap/utils'
|
|
2
|
-
import { useEffect } from 'react'
|
|
3
|
-
import { AppSettings } from '@codeleap/types'
|
|
4
|
-
import { PerformanceError } from './errors'
|
|
5
|
-
|
|
6
|
-
export type InspectRenderOptions = {
|
|
7
|
-
noHooks?: boolean
|
|
8
|
-
logMode?: 'raw' | 'summarized'
|
|
9
|
-
throttleInterval?: number
|
|
10
|
-
maxRenders?: number
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export type PerformanceInspector = {
|
|
14
|
-
inspectRender: (name: string, options?: InspectRenderOptions) => void
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const renderCounter: Record<string, number> = {}
|
|
18
|
-
|
|
19
|
-
export function makePerformanceInspector(settings: AppSettings) {
|
|
20
|
-
/**
|
|
21
|
-
* inspectRender monitors how much time a component render per second.
|
|
22
|
-
* Use perf.inspectRender('ComponentName') inside a component to monitor it.
|
|
23
|
-
* @param {string} name - Component name
|
|
24
|
-
* @param {PerformanceInspector} options - Some options for the inspector
|
|
25
|
-
* @returns
|
|
26
|
-
*/
|
|
27
|
-
const inspectRender = (
|
|
28
|
-
name: string,
|
|
29
|
-
options: InspectRenderOptions = {
|
|
30
|
-
noHooks: false,
|
|
31
|
-
logMode: 'summarized',
|
|
32
|
-
throttleInterval: 1000,
|
|
33
|
-
maxRenders: settings?.PerformanceInspector.maxRenders,
|
|
34
|
-
},
|
|
35
|
-
) => {
|
|
36
|
-
const blacklist = settings?.PerformanceInspector.blacklist || []
|
|
37
|
-
if (blacklist.some((item) => name.startsWith(item))) return
|
|
38
|
-
|
|
39
|
-
const { noHooks, logMode, throttleInterval, maxRenders } = options
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
!settings?.PerformanceInspector.enable ||
|
|
43
|
-
!settings?.Environment.IsDev
|
|
44
|
-
) {
|
|
45
|
-
return
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (!noHooks) {
|
|
49
|
-
useEffect(() => {
|
|
50
|
-
console.log(`[PerformanceInspector] Mounted -> ${name}`)
|
|
51
|
-
|
|
52
|
-
return () => {
|
|
53
|
-
console.log(`[PerformanceInspector] Unmounted -> ${name}`)
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
renderCounter[name] = renderCounter[name] ? renderCounter[name] + 1 : 1
|
|
59
|
-
const renders = renderCounter[name]
|
|
60
|
-
|
|
61
|
-
if (renders > maxRenders) {
|
|
62
|
-
renderCounter[name] = 0
|
|
63
|
-
throw new PerformanceError('maxRenders', {
|
|
64
|
-
name,
|
|
65
|
-
throttleInterval,
|
|
66
|
-
maxRenders,
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (logMode === 'raw') {
|
|
71
|
-
console.log(`[PerformanceInspector] Rendered -> ${name}: ${renders}`)
|
|
72
|
-
return
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function logSummary() {
|
|
76
|
-
if (renders <= 0) return
|
|
77
|
-
|
|
78
|
-
console.log(`[PerformanceInspector] Render summary -> ${name}: ${renders}`)
|
|
79
|
-
renderCounter[name] = 0
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
throttle(logSummary, name, throttleInterval)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return { inspectRender }
|
|
86
|
-
}
|