5 min read

console.logλ§ŒμœΌλ‘œλŠ” λΆ€μ‘±ν–ˆλ˜ μ–΄λŠ λ‚ μ˜ 디버깅 기둝

Table of Contents

κ°œλ°œμ„ ν•˜λ‹€ 보면 λˆ„κ΅¬λ‚˜ ν•œ 번쯀 λ§ˆμ£Όν•˜λŠ” 풍경이 μžˆμŠ΅λ‹ˆλ‹€. μ½˜μ†”μ°½ 가득 λ©”μ›Œμ§„ 111, here, obj 같은 의미 μ—†λŠ” λ¬Έμžμ—΄λ“€. κΈ‰ν•œ λ§ˆμŒμ— μΆ”κ°€ν•œ console.logλŠ” λ‹Ήμž₯의 λΆˆμ„ λ„λŠ” λ°λŠ” 도움이 λ˜μ§€λ§Œ, ν”„λ‘œμ νŠΈμ˜ 규λͺ¨κ°€ 컀지고 λΉ„μ¦ˆλ‹ˆμŠ€ 둜직이 λ³΅μž‘ν•΄μ§ˆμˆ˜λ‘ 였히렀 μ†ŒμŒμ΄ λ˜μ–΄ 우리의 λˆˆμ„ 가리곀 ν•©λ‹ˆλ‹€.

μ € μ—­μ‹œ μ–Όλ§ˆ μ „, μˆ˜μ‹­ 개의 API 응닡과 λ³΅μž‘ν•œ μƒνƒœ λ³€ν™”κ°€ μ–½νžŒ 결제 λ‘œμ§μ„ λ””λ²„κΉ…ν•˜λ©° λΉ„μŠ·ν•œ κ²½ν—˜μ„ ν–ˆμŠ΅λ‹ˆλ‹€. console.logλ§ŒμœΌλ‘œλŠ” λ„μ €νžˆ λ°μ΄ν„°μ˜ 흐름을 쫓을 수 μ—†μ—ˆλ˜ κ·Έ μˆœκ°„, μ €λŠ” μš°λ¦¬κ°€ 무심코 μ§€λ‚˜μ³€λ˜ console 객체의 μ§„μ •ν•œ κ°€μΉ˜λ₯Ό λ‹€μ‹œκΈˆ κΉ¨λ‹«κ²Œ λ˜μ—ˆμŠ΅λ‹ˆλ‹€. 이번 κΈ€μ—μ„œλŠ” λ‹¨μˆœν•œ 좜λ ₯을 λ„˜μ–΄, β€˜κ΄€μΈ‘ κ°€λŠ₯μ„±(Observability)β€˜μ˜ κ΄€μ μ—μ„œ console을 μ–΄λ–»κ²Œ ν™œμš©ν•  수 μžˆλŠ”μ§€ κ·Έ 고민의 과정을 κ³΅μœ ν•˜λ € ν•©λ‹ˆλ‹€.


1. λ°μ΄ν„°μ˜ ν˜•μƒμ— μ§‘μ€‘ν•˜κΈ°: console.table

μš°λ¦¬λŠ” 보톡 API 응닡을 ν™•μΈν•˜κΈ° μœ„ν•΄ μŠ΅κ΄€μ μœΌλ‘œ console.log(response)λ₯Ό νƒ€μ΄ν•‘ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ 응닡 데이터가 μˆ˜μ‹­ 개의 ν•„λ“œλ₯Ό κ°€μ§„ 객체 배열이라면 μ–΄λ–¨κΉŒμš”? λΈŒλΌμš°μ € μ½˜μ†”μ—μ„œ ν™”μ‚΄ν‘œλ₯Ό 일일이 ν΄λ¦­ν•˜λ©° ν•„λ“œλ₯Ό ν™•μΈν•˜λŠ” 과정은 κ·Έ 자체둜 인지 λΆ€ν•˜λ₯Ό μΌμœΌν‚΅λ‹ˆλ‹€.

β€ν‘œ(Table)λŠ” 인지 λΆ€ν•˜λ₯Ό μ€„μ΄λŠ” κ°€μž₯ κ°•λ ₯ν•œ λ„κ΅¬μž…λ‹ˆλ‹€β€

Toss Tech의 κΈ€μ—μ„œ μΈν„°νŽ˜μ΄μŠ€λ₯Ό β€˜κ³„μ•½β€™μœΌλ‘œ 바라보듯, μ €λŠ” 둜그 μ—­μ‹œ β€˜λ°μ΄ν„°μ˜ 계약’을 ν™•μΈν•˜λŠ” 과정이라고 μƒκ°ν•©λ‹ˆλ‹€. console.table은 이 κ³„μ•½μ˜ 이행 μ—¬λΆ€λ₯Ό κ°€μž₯ λͺ…ν™•ν•˜κ²Œ λ³΄μ—¬μ€λ‹ˆλ‹€.

// λ³΅μž‘ν•œ μ£Όλ¬Έ λͺ©λ‘ 데이터
const orders = [
  { id: 'ORD-001', product: 'MacBook Pro', price: 2500000, status: 'PAID', customer: 'Jungjin' },
  { id: 'ORD-002', product: 'iPad Air', price: 900000, status: 'PENDING', customer: 'Antigravity' },
  { id: 'ORD-003', product: 'iPhone 15', price: 1200000, status: 'FAILED', customer: 'Toss' },
]

// λ‹¨μˆœνžˆ log둜 찍으면 객체의 κΉŠμ΄μ— κ°‡νžˆκ²Œ λ˜μ§€λ§Œ,
// table은 λ°μ΄ν„°μ˜ 'ν˜•μƒ'을 ν•œλˆˆμ— λ“œλŸ¬λƒ…λ‹ˆλ‹€.
console.table(orders, ['id', 'product', 'status'])

μ‹€λ¬΄μ—μ„œμ˜ κ°€μΉ˜: λ‹¨μˆœνžˆ 예쁘게 λ³΄μ—¬μ£ΌλŠ” 것을 λ„˜μ–΄, μ½˜μ†”μ°½μ˜ ν‘œ 헀더λ₯Ό 클릭해 데이터λ₯Ό μ •λ ¬ν•΄ λ³Ό 수 μžˆλ‹€λŠ” 점이 ν•΅μ‹¬μž…λ‹ˆλ‹€. νŠΉμ • μƒνƒœ(FAILED)의 λ°μ΄ν„°λ§Œ λͺ¨μ•„λ³΄κ±°λ‚˜ 가격 순으둜 μ •λ ¬ν•΄ λ³΄λŠ” ν–‰μœ„λŠ” λ³„λ„μ˜ 둜직 μΆ”κ°€ 없이도 즉각적인 뢄석을 κ°€λŠ₯ν•˜κ²Œ ν•©λ‹ˆλ‹€.


2. λ§₯락(Context)을 μžƒμ§€ μ•ŠλŠ” 디버깅: console.group

비동기 μž‘μ—…μ΄ 연달아 μΌμ–΄λ‚˜λŠ” ν™˜κ²½μ—μ„œ λ‘œκ·ΈλŠ” μˆœμ„œκ°€ λ’€μ„žμ΄κΈ° λ§ˆλ ¨μž…λ‹ˆλ‹€. A μž‘μ—…μ˜ λ‘œκ·Έμ™€ B μž‘μ—…μ˜ λ‘œκ·Έκ°€ μ½˜μ†”μ°½μ—μ„œ λ’€μ—‰ν‚€λŠ” μˆœκ°„, μš°λ¦¬λŠ” λ””λ²„κΉ…μ˜ β€˜λ§₯락’을 μžƒμ–΄λ²„λ¦½λ‹ˆλ‹€.

β€λ‘œκ·Έμ—λ„ 계측이 ν•„μš”ν•©λ‹ˆλ‹€β€

μ €λŠ” λ³΅μž‘ν•œ λ‘œμ§μ„ μˆ˜ν–‰ν•  λ•Œ console.group을 톡해 λ‘œκ·Έμ— λͺ…ν™•ν•œ 경계λ₯Ό κΈ‹μŠ΅λ‹ˆλ‹€. μ΄λŠ” 마치 μ½”λ“œμ—μ„œ ν•¨μˆ˜λ₯Ό λΆ„λ¦¬ν•˜λŠ” 것과 같은 논리적 λ‹¨μœ„μ˜ ꡬ뢄을 μ½˜μ†”μ—μ„œλ„ μ‹€ν˜„ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

async function processPayment(orderId) {
  console.group(`πŸ’³ 결제 ν”„λ‘œμ„ΈμŠ€ μ‹œμž‘: ${orderId}`)

  try {
    console.log('1. 재고 확인 쀑...')
    // ... 재고 확인 둜직

    console.groupCollapsed('πŸ” 상세 검증 데이터')
    console.log('ν• μΈμœ¨: 10%')
    console.log('포인트 μ‚¬μš©: 5,000p')
    console.groupEnd()

    console.log('2. PG사 결제 μš”μ²­ 전솑')
    // ... 결제 μš”μ²­ 둜직
  } finally {
    console.groupEnd()
  }
}

μ™œ groupCollapsed인가?: λͺ¨λ“  정보λ₯Ό μ²˜μŒλΆ€ν„° λ‹€ λ³΄μ—¬μ£ΌλŠ” 것은 정보 κ³Όμž‰μž…λ‹ˆλ‹€. groupCollapsedλ₯Ό μ‚¬μš©ν•˜λ©΄ ν‰μ†Œμ—λŠ” 핡심 νλ¦„λ§Œ 보여주닀가, λ¬Έμ œκ°€ 생겼을 λ•Œλ§Œ 상세 λ‚΄μš©μ„ 펼쳐볼 수 μžˆλŠ” β€˜μ„ νƒμ  λ…ΈμΆœβ€™μ΄ κ°€λŠ₯ν•΄μ§‘λ‹ˆλ‹€. μ΄λŠ” 디버깅 μ‹œ μ‹œκ°μ  μ†ŒμŒμ„ μ€„μ΄λŠ” μ‹€μš©μ μΈ μ „λž΅μž…λ‹ˆλ‹€.


3. 보이지 μ•ŠλŠ” 범인 μ°ΎκΈ°: console.count & console.dir

가끔은 둜직이 μ˜λ„μΉ˜ μ•Šκ²Œ μ—¬λŸ¬ 번 μ‹€ν–‰λ˜κ±°λ‚˜, DOM 객체의 λ‚΄λΆ€ 속성이 κΆκΈˆν•  λ•Œκ°€ μžˆμŠ΅λ‹ˆλ‹€. μ΄λ•Œ logλŠ” μš°λ¦¬μ—κ²Œ λ„ˆλ¬΄ λ§Žμ€ 정보λ₯Ό μ£Όκ±°λ‚˜, ν˜Ήμ€ λ„ˆλ¬΄ 적은 정보λ₯Ό μ€λ‹ˆλ‹€.

β€νšŸμˆ˜λ₯Ό μ„ΈλŠ” κ²ƒλ§ŒμœΌλ‘œλ„ λ²„κ·ΈλŠ” μž‘νž™λ‹ˆλ‹€β€

λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈκ°€ μ™œ μ΄λ ‡κ²Œ 자주 λ¦¬λ Œλ”λ§λ˜λŠ”μ§€ κΆκΈˆν•  λ•Œ, console.countλŠ” κ°€μž₯ μ›μ΄ˆμ μ΄λ©΄μ„œλ„ ν™•μ‹€ν•œ 도ꡬ가 λ©λ‹ˆλ‹€.

function MyComponent() {
  // μ»΄ν¬λ„ŒνŠΈκ°€ λ Œλ”λ§λ  λ•Œλ§ˆλ‹€ 횟수λ₯Ό κΈ°λ‘ν•©λ‹ˆλ‹€.
  console.count('πŸ–₯️ MyComponent λ Œλ”λ§ 횟수')
  return <div>Hello World</div>
}

λ˜ν•œ, DOM μš”μ†Œλ₯Ό console.log둜 찍으면 HTML νƒœκ·Έ ν˜•νƒœλ‘œ λ³΄μ΄μ§€λ§Œ, console.dir둜 찍으면 ν•΄λ‹Ή μš”μ†Œκ°€ κ°€μ§„ λͺ¨λ“  μžλ°”μŠ€ν¬λ¦½νŠΈ 속성을 κ³„μΈ΅μ μœΌλ‘œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

// νƒœκ·Έκ°€ μ•„λ‹ˆλΌ '객체'λ‘œμ„œμ˜ 속성이 κΆκΈˆν•  λ•Œ
const button = document.querySelector('button')
console.dir(button)

4. λ‚˜λ§Œμ˜ 디버깅 ν…Œλ§ˆ: CSS Styling (%c)

λ‘œκ·Έκ°€ λ„ˆλ¬΄ λ§Žμ•„ μ€‘μš”ν•œ λ©”μ‹œμ§€κ°€ λ¬»νžŒλ‹€λ©΄, μ•„μ˜ˆ λˆˆμ— λ„κ²Œ μŠ€νƒ€μΌμ„ μž…νž μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” λ‹¨μˆœν•œ 재미λ₯Ό λ„˜μ–΄, λŒ€κ·œλͺ¨ ν”„λ‘œμ νŠΈμ—μ„œ νŠΉμ • λͺ¨λ“ˆμ˜ 둜그λ₯Ό μ‹œκ°μ μœΌλ‘œ κ΅¬λΆ„ν•˜λŠ” 데 맀우 μœ μš©ν•©λ‹ˆλ‹€.

const successStyle =
  'color: white; background: green; font-weight: bold; padding: 2px 5px; border-radius: 3px;'
const errorStyle =
  'color: white; background: red; font-weight: bold; padding: 2px 5px; border-radius: 3px;'

console.log('%c SUCCESS ', successStyle, '데이터 동기화 μ™„λ£Œ')
console.log('%c ERROR ', errorStyle, 'λ„€νŠΈμ›Œν¬ μ—°κ²° μ‹€νŒ¨')

μ‹€μš©μ  포인트: 라이브러리λ₯Ό κ°œλ°œν•˜κ±°λ‚˜ 곡톡 λͺ¨λ“ˆμ„ λ§Œλ“€ λ•Œ, ν•΄λ‹Ή λͺ¨λ“ˆμ—μ„œ λ°œμƒν•˜λŠ” λ‘œκ·Έμ— κ³ μœ ν•œ 색상을 λΆ€μ—¬ν•΄ λ³΄μ„Έμš”. λ‹€λ₯Έ κ°œλ°œμžλ“€μ΄ 둜그λ₯Ό 확인할 λ•Œ β€œμ•„, 이건 κ·Έ λͺ¨λ“ˆμ—μ„œ 보낸 κ±°κ΅¬λ‚˜β€λΌκ³  μ¦‰κ°μ μœΌλ‘œ 인지할 수 있게 λ©λ‹ˆλ‹€.


5. μ„±λŠ₯κ³Ό 좔적, κ·Έ μ΄μƒμ˜ μ‹ λ’°: console.time & trace

가끔은 β€œμ½”λ“œκ°€ λŒμ•„κ°€κΈ΄ ν•˜λŠ”λ°, μ™œ μ΄λ ‡κ²Œ λŠλ¦¬μ§€?” ν˜Ήμ€ β€œμ΄ ν•¨μˆ˜κ°€ μ™œ μ—¬κΈ°μ„œ ν˜ΈμΆœλμ§€?β€λΌλŠ” 근본적인 의문이 λ“€ λ•Œκ°€ μžˆμŠ΅λ‹ˆλ‹€. μ΄λ•Œ μš°λ¦¬λŠ” 감(Intuition)에 μ˜μ‘΄ν•˜κΈ°λ³΄λ‹€ 데이터(Data)에 μ˜μ‘΄ν•΄μ•Ό ν•©λ‹ˆλ‹€.

”츑정할 수 μ—†λ‹€λ©΄ κ°œμ„ ν•  수 μ—†μŠ΅λ‹ˆλ‹€β€

console.time은 μ½”λ“œμ˜ νŠΉμ • ꡬ간이 μ°¨μ§€ν•˜λŠ” 물리적 μ‹œκ°„μ„ μΈ‘μ •ν•΄ μ€λ‹ˆλ‹€. 특히 λ¦¬μ•‘νŠΈμ˜ λ¦¬λ Œλ”λ§ μ΅œμ ν™”λ‚˜ λŒ€λŸ‰μ˜ 데이터 가곡 λ‘œμ§μ—μ„œ 병λͺ© 지점을 μ°ΎλŠ” 데 νƒμ›”ν•©λ‹ˆλ‹€.

console.time('πŸ”₯ 데이터 가곡 μ„±λŠ₯ ν…ŒμŠ€νŠΈ')
const processedData = data.filter((item) => item.active).map(transform)
console.timeEnd('πŸ”₯ 데이터 가곡 μ„±λŠ₯ ν…ŒμŠ€νŠΈ')

λ˜ν•œ, console.traceλŠ” 호좜 μŠ€νƒ(Call Stack)을 κ·ΈλŒ€λ‘œ λ…ΈμΆœν•©λ‹ˆλ‹€. μ΄λŠ” 특히 곡톡 μ»΄ν¬λ„ŒνŠΈλ‚˜ μœ ν‹Έλ¦¬ν‹° ν•¨μˆ˜κ°€ μ˜λ„μΉ˜ μ•Šμ€ κ³³μ—μ„œ ν˜ΈμΆœλ˜μ–΄ λΆ€μˆ˜ 효과(Side Effect)λ₯Ό μΌμœΌν‚¬ λ•Œ, κ·Έ 범인을 μ°ΎλŠ” κ°€μž₯ ν™•μ‹€ν•œ 증거가 λ©λ‹ˆλ‹€.


마치며: μ½˜μ†”μ€ μš°λ¦¬μ™€ μ½”λ“œ μ‚¬μ΄μ˜ λŒ€ν™”μ°½μž…λ‹ˆλ‹€

Toss Tech의 SDK κ°œλ°œκΈ°κ°€ β€˜μ•ˆμ •μ„±β€™κ³Ό β€˜λͺ…확성’을 ν–₯ν•œ μ—¬μ •μ΄μ—ˆλ“―, 우리의 디버깅 κ³Όμ • μ—­μ‹œ μ½”λ“œμ— λŒ€ν•œ μ‹ λ’°λ₯Ό μŒ“μ•„κ°€λŠ” 과정이어야 ν•©λ‹ˆλ‹€. console.log ν•œ 쀄에 μ˜μ‘΄ν•˜λ˜ μŠ΅κ΄€μ—μ„œ λ²—μ–΄λ‚˜ 상황에 λ§žλŠ” μ μ ˆν•œ λ©”μ„œλ“œλ₯Ό μ„ νƒν•˜λŠ” 것, 그것이 λ°”λ‘œ β€˜μ‹€μš©μ£Όμ˜ κ°œλ°œμžβ€™λ‘œμ„œ μš°λ¦¬κ°€ κ°€μ Έμ•Ό ν•  νƒœλ„κ°€ μ•„λ‹κΉŒ μƒκ°ν•©λ‹ˆλ‹€.

λ‹¨μˆœνžˆ ν…μŠ€νŠΈλ₯Ό μ°λŠ” ν–‰μœ„λ₯Ό λ„˜μ–΄, μ‹œμŠ€ν…œμ˜ μƒνƒœλ₯Ό ꡬ쑰적으둜 κ΄€μΈ‘ν•˜κ³  λΆ„μ„ν•˜λŠ” λ„κ΅¬λ‘œμ„œ console을 바라봐 λ³΄μ„Έμš”. μ—¬λŸ¬λΆ„μ˜ μ½˜μ†”μ°½μ΄ μ†ŒμŒμ΄ μ•„λ‹Œ, λͺ…ν™•ν•œ μ‹ ν˜Έ(Signal)둜 가득 μ°¨κΈΈ μ‘μ›ν•©λ‹ˆλ‹€.