Skip to content

Commit e21dce6

Browse files
committed
feat: add the possibility to choose to write a log file
1 parent ac5640b commit e21dce6

File tree

4 files changed

+53
-45
lines changed

4 files changed

+53
-45
lines changed

docs/api/config.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ The configuration follows the `ClarityConfig` interface, which includes:
3636
| `logDirectory` | `string` | `'<project_root>/logs'` | Directory where logs are stored |
3737
| `rotation` | `boolean` \| `RotationConfig` | See below | Log rotation settings |
3838
| `verbose` | `boolean` | `false` | Whether to enable verbose output |
39+
| `writeToFile` | `boolean` | `false` | If `true`, logs are written to disk. If `false`, logs are console-only |
3940

4041
### Default Rotation Configuration
4142

src/config.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ClarityConfig } from './types'
22
import { join, relative, resolve } from 'node:path'
33
import process from 'node:process'
4-
import { loadConfig as bunfigLoadConfig } from 'bunfig'
4+
import { tryLoadConfig as bunfigLoadConfig } from 'bunfig'
55

66
// Get project root directory (where the package.json is located)
77
function getProjectRoot(filePath?: string, options: { relative?: boolean } = {}): string {
@@ -42,22 +42,21 @@ export const defaultConfig: ClarityConfig = {
4242
encrypt: false,
4343
},
4444
verbose: false,
45+
writeToFile: false,
4546
}
4647

4748
// Load config with error handling
4849
async function loadConfig(): Promise<ClarityConfig> {
4950
try {
5051
// const isVerbose = process.env.CLARITY_VERBOSE === 'true' || defaultConfig.verbose
5152

52-
const loadedConfig = await bunfigLoadConfig({
53-
name: 'clarity',
53+
// bunfig.tryLoadConfig expects (name, options)
54+
const loadedConfig = await bunfigLoadConfig('clarity', {
5455
defaultConfig,
5556
cwd: process.cwd(),
56-
endpoint: '',
57-
headers: {},
58-
})
57+
}) as Partial<ClarityConfig> | undefined
5958

60-
return { ...defaultConfig, ...loadedConfig }
59+
return { ...defaultConfig, ...(loadedConfig || {}) }
6160
}
6261
catch {
6362
// If anything fails, return default config

src/logger.ts

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,21 @@ export class Logger {
142142
}
143143
}
144144

145+
private shouldActivateFingersCrossed(level: LogLevel): boolean {
146+
if (!this.fingersCrossedConfig)
147+
return false
148+
149+
const levels: Record<LogLevel, number> = {
150+
debug: 0,
151+
info: 1,
152+
success: 2,
153+
warning: 3,
154+
error: 4,
155+
}
156+
const activation = this.fingersCrossedConfig.activationLevel ?? 'error'
157+
return levels[level] >= levels[activation]
158+
}
159+
145160
private initializeFingersCrossedConfig(options: Partial<ExtendedLoggerOptions>): FingersCrossedConfig | null {
146161
if (!options.fingersCrossedEnabled && options.fingersCrossed) {
147162
return {
@@ -193,6 +208,10 @@ export class Logger {
193208
return mergedOptions
194209
}
195210

211+
private shouldWriteToFile(): boolean {
212+
return !isBrowserProcess() && this.config.writeToFile === true
213+
}
214+
196215
private async writeToFile(data: string): Promise<void> {
197216
// Create a flag to track if this operation has been cancelled
198217
const cancelled = false
@@ -380,6 +399,9 @@ export class Logger {
380399
setupRotation(): void {
381400
if (isBrowserProcess())
382401
return
402+
// Skip rotation entirely when file writing is disabled
403+
if (!this.shouldWriteToFile())
404+
return
383405
if (typeof this.config.rotation === 'boolean')
384406
return
385407

@@ -545,6 +567,8 @@ export class Logger {
545567
private async rotateLog(): Promise<void> {
546568
if (isBrowserProcess())
547569
return
570+
if (!this.shouldWriteToFile())
571+
return
548572

549573
const stats = await stat(this.currentLogFile).catch(() => null)
550574
if (!stats)
@@ -657,10 +681,11 @@ export class Logger {
657681
if (this.shouldActivateFingersCrossed(level) && !this.isActivated) {
658682
this.isActivated = true
659683

660-
// Write all buffered entries
684+
// Write all buffered entries (to file only when enabled)
661685
for (const entry of this.logBuffer) {
662686
const formattedBufferedEntry = await this.formatter.format(entry)
663-
await this.writeToFile(formattedBufferedEntry)
687+
if (this.shouldWriteToFile())
688+
await this.writeToFile(formattedBufferedEntry)
664689
// eslint-disable-next-line no-console
665690
console.log(formattedBufferedEntry)
666691
}
@@ -672,41 +697,11 @@ export class Logger {
672697

673698
if (this.isActivated) {
674699
// Direct write when activated
675-
await this.writeToFile(formattedEntry)
700+
if (this.shouldWriteToFile())
701+
await this.writeToFile(formattedEntry)
676702
// eslint-disable-next-line no-console
677703
console.log(formattedEntry)
678704
}
679-
else {
680-
// Buffer the entry
681-
if (this.logBuffer.length >= this.fingersCrossedConfig.bufferSize)
682-
this.logBuffer.shift() // Remove oldest entry
683-
684-
const entry: LogEntry = {
685-
timestamp: new Date(),
686-
level,
687-
message: formattedEntry,
688-
name: this.name,
689-
}
690-
this.logBuffer.push(entry)
691-
}
692-
}
693-
694-
private shouldActivateFingersCrossed(level: LogLevel): boolean {
695-
if (!this.fingersCrossedConfig)
696-
return false
697-
698-
return this.getLevelValue(level) >= this.getLevelValue(this.fingersCrossedConfig.activationLevel)
699-
}
700-
701-
private getLevelValue(level: LogLevel): number {
702-
const levels: Record<LogLevel, number> = {
703-
debug: 0,
704-
info: 1,
705-
success: 2,
706-
warning: 3,
707-
error: 4,
708-
}
709-
return levels[level]
710705
}
711706

712707
private shouldLog(level: LogLevel): boolean {
@@ -1028,8 +1023,9 @@ export class Logger {
10281023
}
10291024
logEntry = logEntry.replace(this.ANSI_PATTERN, '')
10301025

1031-
// Write to file
1032-
await this.writeToFile(logEntry)
1026+
// Write to file only when enabled
1027+
if (this.shouldWriteToFile())
1028+
await this.writeToFile(logEntry)
10331029
}
10341030

10351031
/**
@@ -1090,7 +1086,8 @@ export class Logger {
10901086
}
10911087

10921088
// Write directly to file instead of using this.info()
1093-
await this.writeToFile(logEntry)
1089+
if (this.shouldWriteToFile())
1090+
await this.writeToFile(logEntry)
10941091
}
10951092
}
10961093

@@ -1360,7 +1357,8 @@ export class Logger {
13601357

13611358
// Write directly to file instead of using this.info()
13621359
const logEntry = `${fileTime} ${this.environment}.INFO: [BOX] ${message}\n`.replace(this.ANSI_PATTERN, '')
1363-
await this.writeToFile(logEntry)
1360+
if (this.shouldWriteToFile())
1361+
await this.writeToFile(logEntry)
13641362
}
13651363

13661364
/**

src/types.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ export interface ClarityConfig {
115115
* @default false
116116
*/
117117
verbose: boolean
118+
119+
/**
120+
* Write logs to file system in addition to console output
121+
* @default false
122+
*/
123+
writeToFile?: boolean
118124
}
119125

120126
export type ClarityOptions = Partial<ClarityConfig>
@@ -130,6 +136,10 @@ export interface LoggerOptions {
130136
format?: 'json' | 'text'
131137
rotation?: RotationConfig
132138
timestamp?: string | number | Date
139+
/**
140+
* When true, logs are written to files; when false, logs are console-only
141+
*/
142+
writeToFile?: boolean
133143
fingersCrossed?: boolean | {
134144
activationLevel?: LogLevel
135145
bufferSize?: number

0 commit comments

Comments
 (0)