직딩 개발기-Logger

Lee young-jun
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.errorconsole.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)

--

--

No responses yet