직딩 개발기-Logger
9 min readNov 11, 2023
개발하다보면 디버깅을 해야 하는데요. 킥고잉은 console을 아예 사용할 수 없게 이전 앱 개발 팀장이 정해놔서 매번 디버깅할 때마다 console.log를 추가해서 확인해야 했어요. 😡
그래서 전 로그를 레벨화 하고 개발 중에만 볼 수 있게 로그 환경파일을 아래처럼 만들었어요. (__DEV__를 사용해서 Release에서 출력되지 않게 방지)
export const LogConfig: ILogConfig = {
ble: __DEV__ ? 'none' : 'none',
helmet: __DEV__ ? 'none' : 'none',
pass: __DEV__ ? 'trace' : 'none',
camera: __DEV__ ? 'none' : 'none',
...
}d
함수는 이런 구조로 선언했고요.
export type ILogConfig = { [key in LoggerName]: LoggerLevel }
const isLevelEnabled = (currentLevel: LoggerLevel, targetLevel: LoggerLevel): boolean => {
return LoggerLevels[currentLevel] <= LoggerLevels[targetLevel]
}
export const _log = (logger: LoggerName, level: LoggerLevel, message?: any, ...optionalParams: any[]): void => {
const log = level === 'error' ? console.error : console.log
isLevelEnabled(level, LogConfig[logger]) && log(message, ...optionalParams)
}
export const logError = (logger: LoggerName, message?: any, ...optionalParams: any[]): void => {
__DEV__ && _log(logger, 'error', message, ...optionalParams)
}
하지만 직딩을 개발할 때는 더 세분화하기 위해
export const LogConfig: ILogConfig = {
services: {
data: 'trace',
},
}
구조를 변경하고 새로 선언한 후
export type ILogConfig = {[K: string]: ILoggerConfigValue}
export type ILogLevelConfig = {[K: string]: ILoggerConfigValue}
export type ILoggerConfigValue = LoggerLevel | ILogLevelConfig
호출 함수에서도 LoggerName을 제거했어요.
export const _log = (level: LoggerLevel, targetLevel: LoggerLevel, message?: any, ...optionalParams: any[]): void => {
const log = level === 'error' ? console.error : console.log
isLevelEnabled(level, targetLevel) && log(message, ...optionalParams)
}
export const logError = (level: LoggerLevel, message?: any, ...optionalParams: any[]): void => {
__DEV__ && _log(level, 'error', message, ...optionalParams)
}
하지만 자동완성이 안되는 문제가 생겼어요. 😭
결국 ILogConfig를 제거하고 LoggerLevel을 직접 달아줬습니다.
export const LogConfig = {
services: {
data: 'trace' as LoggerLevel,
holiday: 'none' as LoggerLevel,
},
}
위와 같이 설정하고
import {LogConfig} from '!/logger.config'
logDebug(LogConfig.services.data, 'start initializing')
으로 호출하면 디버깅 할 때 DataService의 Debug 이하 로그만 찍히게 되는 것이죠.
업그레이드
추후에 여기서 조금 더 개선했는 데요.
console.xxx
기존에 console.error
와 console.log
만 사용하던 것을 아래와 같이 각 level에 맞는 console 함수를 사용하도록 수정했습니다.
const logPrinters: {[K in LoggerLevel]: ILogPrinter} = {
trace: console.trace,
debug: console.debug,
info: console.info,
warning: console.warn,
error: console.error,
none: () => {
//
},
}
export const _log = (level: LoggerLevel, targetLevel: LoggerLevel, message?: any, ...optionalParams: any[]): void => {
const log = logPrinters[level]
__DEV__ && isLevelEnabled(level, targetLevel) && log(message, ...optionalParams)
}
logWithLevel
그리고 Level 별로 선언한 log 함수도 중복 코드를 제거했어요.
export const logWithLevel =
(targetLevel: LoggerLevel): ILogWithLevelPrinter =>
(level, message, ...optionalParams): void => {
__DEV__ && _log(level, targetLevel, message, ...optionalParams)
}
export const logError = logWithLevel('error')
export const logWarning = logWithLevel('warning')
export const logInfo = logWithLevel('info')
export const logDebug = logWithLevel('debug')
export const logTrace = logWithLevel('trace')
getLoggers
마지막으로 호출시 Level을 중복으로 기입하지 않고 사용하기 위해 헬퍼를 추가했죠.
export const createLogDelegator =
(logPrinter: ILogWithLevelPrinter, level: LoggerLevel, ...prefixes: any[]): ILogPrinter =>
(message, ...optionalParams): void =>
logPrinter(level, ...prefixes, message, ...optionalParams)
export const getLoggers = (level: LoggerLevel, ...prefixes: any[]) => ({
logError: (message?: string, ...optionalParams: any[]): void => {
logError(level, ...prefixes, message, ...optionalParams)
},
logWarning: (message?: string, ...optionalParams: any[]): void => {
logWarning(level, ...prefixes, message, ...optionalParams)
},
logInfo: (message?: string, ...optionalParams: any[]): void => {
logInfo(level, ...prefixes, message, ...optionalParams)
},
logDebug: (message?: string, ...optionalParams: any[]): void => {
logDebug(level, ...prefixes, message, ...optionalParams)
},
logTrace: (message?: string, ...optionalParams: any[]): void => {
logTrace(level, ...prefixes, message, ...optionalParams)
},
})
이렇게 해서 개선된 최종 사용 방법 입니다.
const __LOG__ = 'DataService'
const {logDebug: log, logTrace} = getLoggers(LogConfig.services.data, __LOG__)
...
log('load next data')
logTrace('next data', data)