🌳λͺ©ν‘œ

λ…Έλ“œμ—μ„œ κ½€ 많이 μ‚¬μš©λ˜λŠ” debug λͺ¨λ“ˆμ„ 직접 λ§Œλ“€μ–΄ λ΄…λ‹ˆλ‹€.

Debugλ₯Ό μ‚¬μš©ν•˜λŠ” 이유

Debug λͺ¨λ“ˆμ€ λ…Έλ“œμ—μ„œ κ°€μž₯ 많이 μ‚¬μš©ν•˜λŠ” 디버깅 λͺ¨λ“ˆμž…λ‹ˆλ‹€. 둜그λ₯Ό ꡬ쑰적으둜 기둝할 수 μžˆλ‹€λŠ” μ μ—μ„œ console.log 보닀 λ›°μ–΄λ‚©λ‹ˆλ‹€. Debugκ°€ κ°–κ³  μžˆλŠ” μž₯점은 μ•„λž˜ 두 κ°€μ§€μž…λ‹ˆλ‹€.

  • νƒœκ·Έλ₯Ό μ§€μ •ν•œ 둜그 ν•¨μˆ˜λ₯Ό λ§Œλ“€ 수 μžˆλ‹€
  • νƒœκ·Έλ³„λ‘œ 색상을 μ€˜μ„œ 둜그 식별이 μˆ˜μ›”ν•˜λ‹€

μ‚¬μš© 방법은 μ•„λž˜μ²˜λŸΌ κ°„λ‹¨ν•©λ‹ˆλ‹€.

const debug = require('debug')('my_tag')
debug('my_log') // "my_tag my_log"

이것을 직접 λ§Œλ“€μ–΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.

ν…ŒμŠ€νŠΈ μ½”λ“œ

ν…ŒμŠ€νŠΈλ₯Ό μ½”λ“œκ°€ μžˆλŠ” 브랜치둜 μ΄λ™ν•˜κ² μŠ΅λ‹ˆλ‹€.

$ git checkout -f module/debug-spec

utils/debug.spec.js에 μžˆλŠ” ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό μ‚΄νŽ΄ λ³΄μ§€μš”. λ„€ λΆ€λΆ„μœΌλ‘œ λ‚˜λˆ„μ–΄ μ„€λͺ…ν•˜κ² μŠ΅λ‹ˆλ‹€.

require('should');
const sinon = require('sinon');
const debug = require('./debug');

describe('debug', () => {
  describe('생성', () => {
    it('νƒœκ·Έλͺ…을 인자둜 λ°›λŠ”λ‹€ (μ—†μœΌλ©΄ μ˜ˆμ™Έλ₯Ό λ˜μ§„λ‹€)', () => {
      should(() => debug()).throw();
    })

ν•„μš”ν•œ λͺ¨λ“ˆμ„ κ°€μ Έμ™€μ„œ μƒμˆ˜μ— ν• λ‹Ήν–ˆμŠ΅λ‹ˆλ‹€. debug λͺ¨λ“ˆμ˜ 생성 μ‹œμ μ˜ κΈ°λŠ₯을 ν…ŒμŠ€νŠΈν•˜λŠ” μ½”λ“œμΈλ° νƒœκ·Έλͺ…을 인자둜 받도둝 ν•©λ‹ˆλ‹€. λ§Œμ•½ νƒœκ·Έ μΈμžκ°€ μ—†μœΌλ©΄ μ˜ˆμ™Έλ₯Ό λ˜μ§€λ„λ‘ ν–ˆμ£ .

    it('ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•œλ‹€', () => {
      const debug = require('./debug')('mytag');
      should(typeof debug).be.equal('function');
    })
  })

νƒœκ·Έλ₯Ό μ „λ‹¬ν•œ ν•¨μˆ˜λŠ” λ‹€μ‹œ ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•˜λŠ”μ§€ typeof둜 μ²΄ν¬ν–ˆμŠ΅λ‹ˆλ‹€.

  describe('λ°˜ν™˜λœ ν•¨μˆ˜', () => {
    let debug, tag, msg;

    beforeEach(() => {
      tag = 'mytag';
      debug = require('./debug')(tag);
      msg = 'my log message';
    })

    it('tag + message ν˜•μ‹μ˜ 둜그 λ¬Έμžμ—΄μ„ λ°˜ν™˜ν•œλ‹€', () => {
      const expected = `${tag} ${msg}`;
      const actual = debug(msg);
      actual.should.be.equal(expected);
    })

이것은 λ°˜ν™˜λœ ν•¨μˆ˜λ₯Ό ν…ŒμŠ€νŠΈν•˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€.

λͺ¨μΉ΄ ν”„λ ˆμž„μ›μ—μ„œ μ œκ³΅ν•˜λŠ” beforeEach() ν•¨μˆ˜λŠ” ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€(it) μ‹€ν–‰ μ „λ§ˆλ‹€ λ™μž‘ν•©λ‹ˆλ‹€. 맀 ν…ŒμŠ€νŠΈμΌ€μ΄μŠ€μ—μ„œ debug 객체λ₯Ό λ§Œλ“€κΈ° λ•Œλ¬Έμ— 쀑볡 μ½”λ“œλ₯Ό 이곳에 λͺ¨μ•„λ…Ό 것이죠. DRY함은 ν…ŒμŠ€νŠΈ μ½”λ“œμ—μ„œλ„ μ˜ˆμ™ΈμΌ 수 μ—†μŠ΅λ‹ˆλ‹€.

λ°˜ν™˜ν•œ ν•¨μˆ˜μ— 메세지(msg)λ₯Ό 전달해 μ‹€ν–‰ν•˜λ©΄ tag + msg λ¬Έμžμ—΄μ΄ λ°˜ν™˜λ˜λŠ”μ§€ μ κ²€ν•˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€.

  it('둜그 λ¬Έμžμ—΄μ„ 인자둜 console.log ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•œλ‹€', () => {
    sinon.spy(console, 'log');
    const expected = `${tag} ${msg}`;

    debug(msg);

    sinon.assert.calledWith(console.log, expected);
  })
})

sinon 라이브러리λ₯Ό μ΄μš©ν•΄μ„œ console.log λ©”μ†Œλ“œμ— 슀파이λ₯Ό μ‹¬μ—ˆμŠ΅λ‹ˆλ‹€. 그리고 dubug(msg)λ₯Ό μ‹€ν–‰ν–ˆμ„ λ•Œ κΈ°λŒ€ν•˜λŠ” λ¬Έμžμ—΄μ΄ console.log ν•¨μˆ˜ 인자둜 μ „λ‹¬λ˜λŠ”μ§€ μ κ²€ν•˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€.

πŸ€μ‹€μŠ΅ - debug λͺ¨λ“ˆμ„ λ§Œλ“€μ–΄ λ΄…λ‹ˆλ‹€

μœ„ ν…ŒμŠ€νŠΈ μ½”λ“œμ—μ„œ μš”κ΅¬ν•˜λŠ” debug λͺ¨λ“ˆμ„ λ§Œλ“€μ–΄ λ³΄μ„Έμš”.

πŸ€ν’€μ΄

잘 ν’€μ–΄ λ³΄μ…¨λ‚˜μš”? utils/debug.js νŒŒμΌμ„ μƒˆλ‘œ λ§Œλ“€μ–΄ 같이 확인해 λ³΄κ² μŠ΅λ‹ˆλ‹€.

const debug = tag => {
  if (!tag) throw Error('tag should be required')
}

module.exports = debug

λ¨Όμ € debugλ₯Ό tag 인자λ₯Ό λ°›λŠ” ν•¨μˆ˜λ‘œ μ •μ˜ ν–ˆμŠ΅λ‹ˆλ‹€. μΈμžκ°€ μ—†μœΌλ©΄ λ°”λ‘œ μ—λŸ¬λ₯Ό λ˜μ§€λ„λ‘ ν•΄μ„œ 첫 번째 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ₯Ό ν†΅κ³Όν•˜λ„λ‘ ν–ˆκ΅¬μš”. λ§ˆμ§€λ§‰μ—” μ—­μ‹œ λͺ¨λ“ˆλ‘œ λ…ΈμΆœν•˜μ˜€μŠ΅λ‹ˆλ‹€.

const debug = tag => {
  // ... 
  return msg => {
    const logString = `${tag} ${msg}`;
    console.log(logString);
    return logString;
  }
// ...

debug ν•¨μˆ˜λŠ” λ‹€μ‹œ ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•˜λ„λ‘ ν–ˆμ£ . κ·Έλž˜μ„œ msgλ₯Ό 인자둜 λ°›λŠ” ν•¨μˆ˜λ₯Ό μ •μ˜ν–ˆμŠ΅λ‹ˆλ‹€. 그런 λ’€ 클둜져둜 캑쳐된 tag κ°’κ³Ό msgλ₯Ό μ‘°ν•©ν•΄μ„œ 둜그 λ¬Έμžμ—΄(logString)을 λ§Œλ“­λ‹ˆλ‹€. 이 값은 console.log와 λ°˜ν™˜ κ°’μœΌλ‘œ μ‚¬μš©ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

그럼 ν…ŒμŠ€νŠΈλ₯Ό 돌렀 λ³ΌκΉŒμš”?

$ npm test

debug
    생성
      βœ“ νƒœκ·Έλͺ…을 인자둜 λ°›λŠ”λ‹€ (μ—†μœΌλ©΄ μ˜ˆμ™Έλ₯Ό λ˜μ§„λ‹€)
      βœ“ ν•¨μˆ˜λ₯Ό λ°˜ν™˜ν•œλ‹€
    λ°˜ν™˜λœ ν•¨μˆ˜
      βœ“ tag + message ν˜•μ‹μ˜ 둜그 λ¬Έμžμ—΄μ„ λ°˜ν™˜ν•œλ‹€
      βœ“ 둜그 λ¬Έμžμ—΄μ„ 인자둜 console.log ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•œλ‹€
    메세지 좜λ ₯ν•¨μˆ˜
      βœ“ _log() ν•¨μˆ˜ κ²°κ³Όλ¬Έμžμ—΄μ„ console.log()ν•¨μˆ˜μ˜ 인자둜 μ „λ‹¬ν•˜μ—¬ μ‹€ν–‰ν•œλ‹€

λͺ¨λ“  ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ— ν†΅κ³Όν–ˆμŠ΅λ‹ˆλ‹€.

πŸ€μ‹€μŠ΅-색상도 μΆ”κ°€ν•΄ λ³΄μ„Έμš”

νƒœν¬ 문자 색상을 랜덀으둜 좜λ ₯ν•˜λ„λ‘ debug λͺ¨λ“ˆμ„ κ°œμ„ ν•΄ λ³΄μ„Έμš”.

힌트: μŠ€νƒμ˜€λ²„ν”Œλ‘œμš° How to change node.js’s console font color

πŸ€ν’€μ΄

νžŒνŠΈκ°€ 도움이 λ˜μ—ˆλ‚˜μš”? 그럼 uitls/debug.jsλ₯Ό 같이 κ°œμ„ ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.

λ¬Έμžμ— 색상을 μΆ”κ°€ν•˜λ €λ©΄ λ‹€μŒκ³Ό 같은 ν˜•μ‹μ΄μ–΄μ•Ό ν•©λ‹ˆλ‹€.

λ¬Έμžμ½”λ“œ + 문자 + λ¦¬μ…‹μ½”λ“œ

λ”°λΌμ„œ 우리 μ½”λ“œ 상단에 μ•„λž˜μ™€ 같이 색상 정보λ₯Ό μΆ”κ°€ν•©λ‹ˆλ‹€.

const colors = [
  {name: 'cyan',     value: '\x1b[36m'},
  {name: 'yellow',   value: '\x1b[33m'},
  {name: 'red',      value: '\x1b[31m'},
  {name: 'green',    value: '\x1b[32m'},
  {name: 'magenta',  value: '\x1b[35m'},
]
const resetColor = '\x1b[0m'

νžŒνŠΈμ—μ„œ μ–ΈκΈ‰ν•œ 것 처럼 색상 μ½”λ“œλ₯Ό λ”•μ…”λ„ˆλ¦¬λ‘œ λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€. 그리고 resetColor도 λ”°λ‘œ μƒμˆ˜λ‘œ λ‘μ—ˆκ΅¬μš”.

const debug = tag => {
  const randIdx = Math.floor(Math.random() * colors.length) % colors.length
  const color = colors[randIdx]

νƒœκ·Έ 인자λ₯Ό λ°›μžλ§ˆμž νƒœκ·Έμ˜ 색상을 μ •ν•˜κΈ° μœ„ν•΄ colors λ°°μ—΄μ—μ„œ 랜덀으둜 인덱슀λ₯Ό κ΅¬ν•˜λŠ” μ½”λ“œ μž…λ‹ˆλ‹€. λ§ˆμ§€λ§‰ color μƒμˆ˜μ—λŠ” name, valueλ₯Ό κ°€μ§€λŠ” 컬러 객체가 랜덀으둜 μ €μž₯ λ˜κ² μ§€μš”.

  return msg => {
    const logString = `${color.value}[${tag}]${resetColor} ${msg}`;
    console.log(logString);
    return logString;
  }

λ°˜ν™˜λœ ν•¨μˆ˜μ—μ„œ 이 랜덀 색상 객체λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€. logString을 λ§Œλ“€λ•Œ νƒœκ·Έ λ¬Έμžμ—΄λ§Œ 색상을 μ§€μ •ν–ˆμŠ΅λ‹ˆλ‹€.

Debug ν™œμš©

우리 μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜ μ½”λ“œμ— 이 debug λͺ¨λ“ˆμ„ μ΄μš©ν•΄μ„œ 둜그λ₯Ό 남겨 λ΄…μ‹œλ‹€.

// app.js
const debug = require('../utils/debug')('app')
// ...

debug('app is initiated')
// bin.js
const debug = require('./utils/debug')('bin')
// ...

app.listen(port, hostname, () => {
  debug(`Server running at http://${hostname}:${port}/`);
// src/Application.js
const debug = require('../utils/debug')('Application')
// ...

  const listen = (port = 3000, hostname = '127.0.0.1', fn) => {
    _server.listen(port, hostname, fn)
    debug('server is listening')
  }

μ„œλ²„λ₯Ό μ‹€ν–‰ν•˜λ©΄ λ‹€μŒκ³Ό 같이 예쁜 λͺ¨μ–‘μ˜ λ‘œκ·Έκ°€ 색상 λ³„λ‘œ λ‚˜μ˜€λŠ” κ±Έ ν™•μΈν• μˆ˜ μžˆμŠ΅λ‹ˆλ‹€.

$ npm start

Debug λͺ¨λ“ˆμ€ μ•„λž˜ μ¨λ“œ νŒŒν‹° 라이브러리 λΆ€λΆ„μž…λ‹ˆλ‹€.

정리

  • μ»€μŠ€ν…€ λͺ¨λ“ˆμΈ debugλ₯Ό λ§Œλ“€μ—ˆμŠ΅λ‹ˆλ‹€.
  • νƒœκ·Έμ™€ μƒ‰μƒμœΌλ‘œ λ‘œκΉ… κΈ°λŠ₯을 κ°œμ„ ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

λͺ©μ°¨ λ°”λ‘œκ°€κΈ°