@stacksjs/logging 0.63.0 → 0.64.0

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/src/index.ts CHANGED
@@ -1,134 +1,126 @@
1
1
  import { access, appendFile, mkdir } from 'node:fs/promises'
2
2
  import { dirname } from 'node:path'
3
3
  import process from 'node:process'
4
- import type { Prompt } from '@stacksjs/cli'
5
- import { buddyOptions, prompt as getPrompt } from '@stacksjs/cli'
4
+ import { prompts } from '@stacksjs/cli'
5
+ import { config } from '@stacksjs/config'
6
6
  import { handleError } from '@stacksjs/error-handling'
7
- import { logsPath } from '@stacksjs/path'
8
7
  import { ExitCode } from '@stacksjs/types'
9
8
  import { isString } from '@stacksjs/validation'
10
- import { consola, createConsola } from 'consola'
11
-
12
- export async function logLevel() {
13
- /**
14
- * This regex checks for:
15
- * - --verbose true or --verbose=true exactly at the end of the string ($ denotes the end of the string).
16
- * - --verbose - followed by optional spaces at the end.
17
- * - --verbose followed by optional spaces at the end.
18
- *
19
- * .trim() is used on options to ensure any trailing spaces in the entire options string do not affect the regex match.
20
- */
21
- const verboseRegex = /--verbose(?!(\s*=\s*false|\s+false))(\s+|=true)?($|\s)/
22
- const opts = buddyOptions()
23
-
24
- if (verboseRegex.test(opts)) return 4
25
-
26
- // const config = await import('@stacksjs/config')
27
- // console.log('config', config)
28
-
29
- return 3
30
- // return config.logger.level
31
- }
32
-
33
- export const logger = createConsola({
34
- level: await logLevel(),
35
- // fancy: true,
36
- // formatOptions: {
37
- // columns: 80,
38
- // colors: false,
39
- // compact: false,
40
- // date: false,
41
- // },
42
- })
43
-
44
- export { consola }
9
+ import isUnicodeSupported from 'is-unicode-supported'
10
+ import color from 'picocolors'
45
11
 
46
12
  export async function writeToLogFile(message: string) {
47
13
  const formattedMessage = `[${new Date().toISOString()}] ${message}\n`
48
14
 
49
15
  try {
50
- const logFilePath = logsPath('console.log')
16
+ const logFile = config.logging.logsPath ?? 'storage/logs/stacks.log'
51
17
 
52
18
  try {
53
19
  // Check if the file exists
54
- await access(logFilePath)
20
+ await access(logFile)
55
21
  } catch {
56
22
  // File doesn't exist, create the directory
57
- await mkdir(dirname(logFilePath), { recursive: true })
23
+ console.log('Creating log file directory...', logFile)
24
+ await mkdir(dirname(logFile), { recursive: true })
58
25
  }
59
26
 
60
27
  // Append the message to the log file
61
- await appendFile(logFilePath, formattedMessage)
28
+ await appendFile(logFile, formattedMessage)
62
29
  } catch (error) {
63
30
  console.error('Failed to write to log file:', error)
64
31
  }
65
32
  }
66
33
 
67
34
  export interface Log {
68
- info: (...args: any[]) => void
69
- success: (msg: string) => void
35
+ info: (message: string, options?: LogMessageOptions) => void
36
+ success: (message: string, options?: LogMessageOptions) => void
70
37
  error: (err: string | Error | unknown, options?: any | Error) => void
71
- warn: (arg: string) => void
72
- debug: (...args: any[]) => void
73
- // start: logger.Start
74
- // box: logger.Box
75
- start: any
76
- box: any
77
- prompt: Prompt
38
+ warn: (message: string, options?: LogMessageOptions) => void
39
+ warning: (message: string, options?: LogMessageOptions) => void
40
+ debug: (message: string, options?: LogMessageOptions) => void
41
+ message: (message: string, options?: LogMessageOptions) => void
42
+ step: (message: string, options?: LogMessageOptions) => void
78
43
  dump: (...args: any[]) => void
79
44
  dd: (...args: any[]) => void
80
45
  echo: (...args: any[]) => void
81
46
  }
82
47
 
48
+ const unicode = isUnicodeSupported()
49
+ const s = (c: string, fallback: string) => (unicode ? c : fallback)
50
+ const S_INFO = s('●', '•')
51
+ const S_SUCCESS = s('◆', '*')
52
+ const S_WARN = s('▲', '!')
53
+ const S_ERROR = s('■', 'x')
54
+ const S_BAR = s('│', '|')
55
+ const S_STEP_SUBMIT = s('◇', 'o')
56
+
57
+ export type LogMessageOptions = {
58
+ symbol?: string
59
+ styled?: boolean
60
+ }
61
+
83
62
  export const log: Log = {
84
- async info(...arg: any) {
85
- // @ts-expect-error intentional
86
- logger.info(...arg)
87
- await writeToLogFile(`INFO: ${arg}`)
88
- },
63
+ message: (message = '', { symbol = color.gray(S_BAR), styled = true }: LogMessageOptions = {}) => {
64
+ if (!styled) return process.stdout.write(`${message}\n`)
89
65
 
90
- async success(msg: string) {
91
- logger.success(msg)
92
- await writeToLogFile(`SUCCESS: ${msg}`)
93
- },
66
+ const parts = [`${color.gray(S_BAR)}`]
94
67
 
95
- async error(err: unknown, options?: any | Error) {
96
- if (err instanceof Error) handleError(err, options)
97
- else if (options instanceof Error) handleError(options)
98
- else handleError(err, options)
68
+ if (message) {
69
+ const [firstLine, ...lines] = message.split('\n')
70
+ parts.push(`${symbol} ${firstLine}`, ...lines.map((ln) => `${color.gray(S_BAR)} ${ln}`))
71
+ }
99
72
 
100
- await writeToLogFile(`ERROR: ${err}`)
73
+ process.stdout.write(`${parts.join('\n')}\n`)
101
74
  },
102
75
 
103
- async warn(arg: string) {
104
- logger.warn(arg)
105
- await writeToLogFile(`WARN: ${arg}`)
76
+ info: async (message: string, options?: LogMessageOptions) => {
77
+ log.message(message, { symbol: color.blue(S_INFO), ...options })
78
+ await writeToLogFile(`INFO: ${message}`)
106
79
  },
107
80
 
108
- async debug(...arg: any) {
109
- if (process.env.APP_ENV === 'production' || process.env.APP_ENV === 'prod')
110
- return await writeToLogFile(`DEBUG: ${arg}`)
81
+ success: async (message: string, options?: LogMessageOptions) => {
82
+ log.message(message, { symbol: color.green(S_SUCCESS), ...options })
83
+ await writeToLogFile(`SUCCESS: ${message}`)
84
+ },
111
85
 
112
- logger.debug(arg)
86
+ step: async (message: string, options?: LogMessageOptions) => {
87
+ log.message(message, { symbol: color.green(S_STEP_SUBMIT), ...options })
88
+ await writeToLogFile(`STEP: ${message}`)
89
+ },
90
+
91
+ warn: async (message: string, options?: LogMessageOptions) => {
92
+ log.message(message, { symbol: color.yellow(S_WARN), ...options })
93
+ await writeToLogFile(`WARN: ${message}`)
94
+ },
113
95
 
114
- if (isString(arg)) await writeToLogFile(`DEBUG: ${arg}`)
115
- else await writeToLogFile(`DEBUG: ${JSON.stringify(arg)}`)
96
+ /** alias for `log.warn()`. */
97
+ warning: (message: string, options?: LogMessageOptions) => {
98
+ log.warn(message, options)
116
99
  },
117
100
 
118
- async start(...arg: any) {
119
- logger.start(arg)
120
- await writeToLogFile(`START: ${arg}`)
101
+ error: (err: unknown, options?: any | Error) => {
102
+ if (err instanceof Error) handleError(err, options)
103
+ else if (err instanceof Error) handleError(options)
104
+ else handleError(err, options)
105
+
106
+ const errorMessage = isString(err) ? err : err instanceof Error ? err.message : String(err)
107
+ log.message(errorMessage, { symbol: color.red(S_ERROR) })
108
+ writeToLogFile(`ERROR: ${errorMessage}`)
121
109
  },
122
110
 
123
- box: logger.box,
111
+ debug: (...args: any[]) => {
112
+ if (process.env.APP_ENV === 'production' || process.env.APP_ENV === 'prod')
113
+ return writeToLogFile(`DEBUG: ${args.join(' ')}`)
124
114
 
125
- get prompt() {
126
- return getPrompt()
115
+ writeToLogFile(`DEBUG: ${args.join(' ')}`)
127
116
  },
128
117
 
129
- dump,
130
- dd,
131
- echo,
118
+ dump: (...args: any[]) => args.forEach((arg) => console.log(arg)),
119
+ dd: (...args: any[]) => {
120
+ args.forEach((arg) => console.log(arg))
121
+ process.exit(ExitCode.FatalError)
122
+ },
123
+ echo: (...args: any[]) => console.log(...args),
132
124
  }
133
125
 
134
126
  export function dump(...args: any[]) {