Skip to content

Commit

Permalink
Merge branch 'release/v0.17.7'
Browse files Browse the repository at this point in the history
  • Loading branch information
holtwick committed Mar 15, 2024
2 parents d91624b + a190019 commit 4418217
Show file tree
Hide file tree
Showing 15 changed files with 171 additions and 43 deletions.
6 changes: 4 additions & 2 deletions demos/logging/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
/* eslint-disable no-console */

import process from 'node:process'
import { Logger, setupEnv } from 'zeed'
import { Logger, logCaptureConsole, setupEnv } from 'zeed'

// Read .env file

setupEnv({ mode: 'test' })

// Some basic logging

logCaptureConsole(Logger('console'))

{
const log = Logger('demo')
log('Hello World')
Expand All @@ -28,7 +30,7 @@ setupEnv({ mode: 'test' })
log.warn('Warning')
log.error('Error')

log('Some binary data', new Uint8Array(1, 2, 3, 99, 100, 101))
log('Some binary data', new Uint8Array([1, 2, 3, 99, 100, 101]))
}

console.log('Hello World')
Expand Down
2 changes: 1 addition & 1 deletion demos/logging/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@
"filtered": "LEVEL=info ZEED=demo2 node index.js"
},
"dependencies": {
"zeed": "file:../.."
"zeed": "../.."
}
}
10 changes: 5 additions & 5 deletions demos/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.4.5"
"vue": "^3.4.21"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.2",
"@vue/compiler-sfc": "^3.4.5",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/compiler-sfc": "^3.4.21",
"@vuedx/typecheck": "^0.7.6",
"@vuedx/typescript-plugin-vue": "^0.7.6",
"typescript": "^5.3.3",
"vite": "^5.0.11"
"typescript": "^5.4.2",
"vite": "^5.1.6"
}
}
3 changes: 3 additions & 0 deletions demos/vite/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<script lang="ts">
import { defineComponent } from 'vue'
import HelloWorld from './components/HelloWorld.vue'
import { logTest } from './log-test'
logTest()
export default defineComponent({
name: 'App',
Expand Down
30 changes: 30 additions & 0 deletions demos/vite/src/log-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* eslint-disable no-console */
import { logCaptureConsole } from '../../../src/common'
import { Logger } from '../../../src/index.browser'

export function logTest() {
logCaptureConsole(Logger('console'))

{
const log = Logger('demo')
log('Hello World')
log.info('Info')
log.warn('Warning')
log.error('Error')
}

{
const log = Logger('demo2')
log('Hello World')
log.info('Info')
log.warn('Warning')
log.error('Error')

log('Some binary data', new Uint8Array([1, 2, 3, 99, 100, 101]))
}

console.log('Hello World')
console.info('Info')
console.warn('Warning')
console.error('Error')
}
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "zeed",
"type": "module",
"version": "0.17.6",
"version": "0.17.7",
"description": "🌱 Simple foundation library",
"author": {
"name": "Dirk Holtwick",
Expand Down Expand Up @@ -62,18 +62,18 @@
"start": "nr watch",
"test": "nr build && vitest",
"test:publish": "vitest --run",
"watch": "nr build -- --watch"
"watch": "nr build -- --watch src"
},
"devDependencies": {
"@antfu/eslint-config": "^2.8.1",
"@antfu/eslint-config": "^2.8.3",
"@antfu/ni": "^0.21.12",
"@types/node": "^20.11.26",
"@vitest/coverage-v8": "^1.3.1",
"esbuild": "^0.20.1",
"@types/node": "^20.11.28",
"@vitest/coverage-v8": "^1.4.0",
"esbuild": "^0.20.2",
"eslint": "^8.57.0",
"tsup": "^8.0.2",
"typescript": "^5.4.2",
"vite": "^5.1.6",
"vitest": "^1.3.1"
"vitest": "^1.4.0"
}
}
55 changes: 38 additions & 17 deletions src/browser/log/log-browser-factory.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/* eslint-disable no-console */

import type { LogHandlerOptions, LogLevel, LogLevelAliasType, LoggerInterface } from '../../common/log/log-base'
import { LogLevelAll, LogLevelDebug, LogLevelError, LogLevelFatal, LogLevelInfo, LogLevelOff, LogLevelWarn } from '../../common/log/log-base'
import { browserSelectColorByName } from '../../common/log/log-colors'
import { getGlobalConsole } from '../../common/log/log-console-original'
import { parseLogLevel, useNamespaceFilter } from '../../common/log/log-filter'
import { browserSupportsColors } from './log-colors'

Expand All @@ -19,9 +18,11 @@ export function LoggerBrowserSetupDebugFactory(opt: LogHandlerOptions = {}) {
const useColors = browserSupportsColors()
const noop: any = () => {}

/// The trick is, that console called directly provides a reference to the source code.
/// For the regular implementation this information is lost. But this approach has other
/// drawbacks, therefore only use it in the Browser when actively debugging.
/**
* The trick is, that console called directly provides a reference to the source code.
* For the regular implementation this information is lost. But this approach has other
* drawbacks, therefore only use it in the Browser when actively debugging.
*/
return function LoggerBrowserDebugFactory(
name = '',
logLevel?: LogLevelAliasType,
Expand All @@ -32,7 +33,7 @@ export function LoggerBrowserSetupDebugFactory(opt: LogHandlerOptions = {}) {
const level = parseLogLevel(logLevel ?? LogLevelAll)

if (matches(name) && level !== LogLevelOff) {
const fixedArgs = []
const fixedArgs: string[] = []
if (useColors) {
const color = browserSelectColorByName(name)
fixedArgs.push(`%c${name.padEnd(16, ' ')}%c \t%s`)
Expand All @@ -49,11 +50,31 @@ export function LoggerBrowserSetupDebugFactory(opt: LogHandlerOptions = {}) {
return () => {}
}

log = defineForLogLevel(LogLevelDebug, console.debug.bind(console, ...fixedArgs) as LoggerInterface)
log.debug = defineForLogLevel(LogLevelDebug, console.debug.bind(console, ...fixedArgs))
log.info = defineForLogLevel(LogLevelInfo, console.info.bind(console, ...fixedArgs))
log.warn = defineForLogLevel(LogLevelWarn, console.warn.bind(console, ...fixedArgs))
log.error = defineForLogLevel(LogLevelError, console.error.bind(console, ...fixedArgs))
// logCaptureConsole will override the console methods, so we need to get the original ones
const originalConsole = getGlobalConsole()

log = defineForLogLevel(LogLevelDebug, originalConsole.debug.bind(originalConsole.console, ...fixedArgs) as LoggerInterface)
log.debug = defineForLogLevel(LogLevelDebug, originalConsole.debug.bind(originalConsole.console, ...fixedArgs))
log.info = defineForLogLevel(LogLevelInfo, originalConsole.info.bind(originalConsole.console, ...fixedArgs))
log.warn = defineForLogLevel(LogLevelWarn, originalConsole.warn.bind(originalConsole.console, ...fixedArgs))
log.error = defineForLogLevel(LogLevelError, originalConsole.error.bind(originalConsole.console, ...fixedArgs))

/**
* Takes log level as argument, but will fail to show all the debug info
* as the others do like file name and line number of the originating call
*/
log.generic = (logLevel: LogLevel, ...args) => {
if (level <= logLevel) {
if (logLevel === LogLevelError)
originalConsole.error(...fixedArgs, ...args)
else if (logLevel === LogLevelWarn)
originalConsole.warn(...fixedArgs, ...args)
else if (logLevel === LogLevelInfo)
originalConsole.info(...fixedArgs, ...args)
else
originalConsole.debug(...fixedArgs, ...args)
}
}

log.fatal = defineForLogLevel(LogLevelFatal, (...args: any) => {
log.error(...args)
Expand Down Expand Up @@ -85,12 +106,12 @@ export function LoggerBrowserSetupDebugFactory(opt: LogHandlerOptions = {}) {
}
}

/** @deprecated This output is default for initial use of Logger in browser environments. */
export function activateConsoleDebug(_opt: LogHandlerOptions = {}) {
console.info('activateConsoleDebug is activated by default in browsers')
// Logger.setHandlers([LoggerBrowserHandler(opt)]) // Fallback for previously registered Loggers
// Logger.setFactory(LoggerBrowserSetupDebugFactory(opt))
}
// /** @deprecated This output is default for initial use of Logger in browser environments. */
// export function activateConsoleDebug(_opt: LogHandlerOptions = {}) {
// console.info('activateConsoleDebug is activated by default in browsers')
// // Logger.setHandlers([LoggerBrowserHandler(opt)]) // Fallback for previously registered Loggers
// // Logger.setFactory(LoggerBrowserSetupDebugFactory(opt))
// }

// let klass = console
// let debug = console.debug.bind(window.console, klass.toString() + ": ")
Expand Down
5 changes: 3 additions & 2 deletions src/browser/log/log-browser.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
/* eslint-disable no-console */

import type { LogHandler, LogHandlerOptions, LogMessage } from '../../common/log/log-base'
import { LogLevelError, LogLevelInfo, LogLevelWarn } from '../../common/log/log-base'
import { browserSelectColorByName } from '../../common/log/log-colors'
import { getGlobalConsole } from '../../common/log/log-console-original'
import { useLevelFilter, useNamespaceFilter } from '../../common/log/log-filter'
import { formatMilliseconds, getTimestamp } from '../../common/time'
import { browserSupportsColors } from './log-colors'
Expand Down Expand Up @@ -78,6 +77,8 @@ export function LoggerBrowserHandler(opt: LogHandlerOptions = {}): LogHandler {
return arg
}) as any

const console = getGlobalConsole()

switch (msg.level) {
case LogLevelInfo:
if (opt.levelHelper)
Expand Down
3 changes: 0 additions & 3 deletions src/common/data/convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,11 @@ export function formatMessages(
if (obj && typeof obj === 'object') {
if (pretty && (obj instanceof Uint8Array || obj instanceof ArrayBuffer))
return `\n${Uint8ArrayToHexDump(obj)}\n`

if (obj instanceof Error) {
if (!trace)
return `${obj.name || 'Error'}: ${obj.message}`

return `${obj.name || 'Error'}: ${obj.message}\n${obj.stack}`
}

try {
return pretty ? JSON.stringify(obj, null, 2) : JSON.stringify(obj)
}
Expand Down
2 changes: 2 additions & 0 deletions src/common/log/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export * from './log'
export * from './log-base'
export * from './log-colors'
export * from './log-console'
export * from './log-console-original'
export * from './log-console-capture'
export * from './log-context'
export * from './log-filter'
export * from './log-memory'
2 changes: 2 additions & 0 deletions src/common/log/log-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ export interface LoggerInterface {

level: LogLevel

generic: (level: LogLevel, ...messages: any[]) => void

debug: (...messages: any[]) => void

info: (...messages: any[]) => void
Expand Down
33 changes: 33 additions & 0 deletions src/common/log/log-console-capture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { LoggerInterface } from './log-base'
import { LogLevelDebug, LogLevelError, LogLevelInfo, LogLevelWarn } from './log-base'

let onlyOnce: boolean | undefined

/**
* Overrides the global console methods to capture log messages and forward them to the provided logger.
* Also captures window errors and unhandled rejections and logs them using the provided logger.
*
* @param log - The logger to which the captured log messages will be forwarded.
*/
export function logCaptureConsole(log: LoggerInterface) {
if (onlyOnce) {
log.error('use logCaptureConsole only once!')
return
}

onlyOnce = true

globalThis.console.log = (...args: any[]) => log.generic(LogLevelDebug, ...args)
globalThis.console.debug = (...args: any[]) => log.generic(LogLevelDebug, ...args)
globalThis.console.warn = (...args: any[]) => log.generic(LogLevelWarn, ...args)
globalThis.console.error = (...args: any[]) => log.generic(LogLevelError, ...args)
globalThis.console.info = (...args: any[]) => log.generic(LogLevelInfo, ...args)

globalThis.addEventListener?.('unhandledrejection', (event: any) => {
log.generic(LogLevelError, 'onUnhandledrejection', event)
})

globalThis.addEventListener?.('error', (event: any) => {
log.generic(LogLevelError, 'onError', event)
})
}
32 changes: 32 additions & 0 deletions src/common/log/log-console-original.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { getGlobalContext } from '../global'

// Global logger to guarantee all submodules use the same logger instance

export type OriginalConsole = Pick<Console, 'log' | 'info' | 'warn' | 'error' | 'debug' > & { console: Console }

declare global {
interface ZeedGlobalContext {
originalConsole?: OriginalConsole
}
}

/**
* Retrieves the global console object, ensuring that it is stored in the global context.
* If the global context does not have a reference to the original console object, it creates one.
* The original console object is then bound to the global context, allowing access to its methods.
*/
export function getGlobalConsole(): OriginalConsole {
const gcontext = getGlobalContext()
if (gcontext.originalConsole == null) {
const originalConsole = console
gcontext.originalConsole = {
console: originalConsole,
log: originalConsole.log.bind(originalConsole),
info: originalConsole.info.bind(originalConsole),
warn: originalConsole.warn.bind(originalConsole),
error: originalConsole.error.bind(originalConsole),
debug: originalConsole.debug.bind(originalConsole),
}
}
return gcontext.originalConsole
}
11 changes: 6 additions & 5 deletions src/common/log/log-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ export function LoggerContext(_prefix = ''): LoggerContextInterface {
}

const log = defineForLogLevel(LogLevelDebug, (...messages: any[]) => {
emit({
name,
messages,
level: LogLevelDebug,
})
emit({ name, messages, level: LogLevelDebug })
})

log.generic = function (level: LogLevel, ...messages: any[]) {
if (logLevel <= level)
emit({ name, messages, level })
}

log.label = name
// log.active = true

Expand Down
6 changes: 5 additions & 1 deletion src/common/log/log.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { getGlobalContext } from '../global'
import type { LogLevelAliasType, LoggerContextInterface, LoggerInterface } from './log-base'
import { LoggerContext } from './log-context'
import { LoggerConsoleHandler } from './log-console'
import { getGlobalConsole } from './log-console-original'
import { LoggerContext } from './log-context'

// Global logger to guarantee all submodules use the same logger instance

Expand All @@ -22,11 +23,14 @@ function getLoggerContext(setup?: (context: LoggerContextInterface) => void) {
return logger
}

/** Get or create global logger instance */
export function getGlobalLogger(setup?: (context: LoggerContextInterface) => void): LoggerContextInterface {
if (globalLogger == null) {
try {
const gcontext = getGlobalContext()
if (gcontext != null) {
getGlobalConsole()

if (gcontext?.logger == null) {
globalLogger = getLoggerContext(setup)
gcontext.logger = globalLogger
Expand Down

0 comments on commit 4418217

Please sign in to comment.