Graphics Programming

RAII 이용해서 간단하게 로그 남기기 본문

Season 1/Misc

RAII 이용해서 간단하게 로그 남기기

minseoklee 2018. 2. 3. 12:14

로그를 찍을 때 작업의 디테일한 정도나 호출 순서를 알아보기 쉽게 하려고 들여쓰기를 쓰는 경우가 있다.


단순한 상황으로 함수 A 안에서 함수 B를 호출할 때, 콘솔에 A를 쓰고 들여쓰기한 다음 B를 쓴다고 치자.


#include <iostream>


void A() {

    std::cout << "A" << std::endl;

    B();

    // do something

}


void B() {

    std::cout << "\tB" << std::endl;

    // do something

}


타자를 줄이기 위해 매크로를 정의한다.


#include <iostream>


#define LOG(x) { std::cout << x << std::endl; }


void A() {

    LOG("A")

    B();

    // do something

}


void B() {

    LOG("\tB")

    // do something

}


탭을 직접 찍을 필요는 없는 것 같다. 탭도 매크로로 만든다.


#include <iostream>

#include <string>


static int __tabCount = 0;

static std::string __tabString = "";


#define LOG(x) { std::cout << __tabString << x << std::endl; }

#define TAB() { __tabCount++; __tabString = std::string(__tabCount, '\t'); }

#define UNTAB() { __tabCount--; __tabString = std::string(__tabCount, '\t'); }


void A() {

    LOG("A")

    TAB()


    B();

    // do something


    UNTAB()

}


void B() {

    LOG("B")

    // do something

}


함수 이름을 로그에 찍는 것이 목적이었다.


#include <iostream>

#include <string>


static int __tabCount = 0;

static std::string __tabString = "";


#define LOG(x) { std::cout << __tabString << x << std::endl; }

#define FUNCNAME() LOG(__FUNCTION__)

#define TAB() { __tabCount++; __tabString = std::string(__tabCount, '\t'); }

#define UNTAB() { __tabCount--; __tabString = std::string(__tabCount, '\t'); }


void A() {

    FUNCNAME()

    TAB()


    B();

    // do something


    UNTAB()

}


void B() {

    FUNCNAME()

    // do something

}


그런데 이렇게 하면 항상 함수 첫머리에 FUNCNAME()과 TAB()을 쓰고 종료 직전에 UNTAB()을 써야 한다. 함수 중간에 return이라도 있으면 더 귀찮다. 탭이 꼬이지 않게 일일이 UNTAB()을 넣어야 한다.


#include <iostream>

#include <string>


static int __tabCount = 0;

static std::string __tabString = "";


#define LOG(x) { std::cout << __tabString << x << std::endl; }

#define FUNCNAME() LOG(__FUNCTION__)

#define TAB() { __tabCount++; __tabString = std::string(__tabCount, '\t'); }

#define UNTAB() { __tabCount--; __tabString = std::string(__tabCount, '\t'); }


void A() {

    FUNCNAME()

    TAB()


    if(foo == bar) {

        UNTAB()

        return;

    }


    B();


    if(baz == nullptr) {

        UNTAB()

        return;

    }


    UNTAB()

}


void B() {

    FUNCNAME()

    // do something

}


이럴 때는 생성자에 FUNCNAME()과 TAB()이 있고 소멸자에 UNTAB()이 있는 구조체를 하나 정의하면 일이 편해진다.


#include <iostream>

#include <string>


static int __tabCount = 0;

static std::string __tabString = "";


#define LOG(x) { std::cout << __tabString << x << std::endl; }

#define FUNCNAME() LogFuncName __logFuncName(__FUNCTION__);

#define TAB() { __tabCount++; __tabString = std::string(__tabCount, '\t'); }

#define UNTAB() { __tabCount--; __tabString = std::string(__tabCount, '\t'); }

struct LogFuncName {

LogFuncName(const char* fname) {

LOG(fname)

TAB()

}

~LogFuncName() { UNTAB() }

};


void A() {

    FUNCNAME()


    if(foo == bar) {

        return;

    }


    B();


    if(baz == nullptr) {

        return;

    }

}


void B() {

    FUNCNAME()

    // do something

}


주의점

  • LogFuncName 안에서 __FUNCTION__을 쓰면 "LogFuncName"이 찍히기 때문에 함수 이름 문자열을 인자로 받는다.
  • FUNCNAME()의 정의가 { LogFuncName __logFucName(__FUNCTION__); } 이 아니라 LogFuncName __logFucName(__FUNCTION__); 이다. 중괄호로 감싸면 구조체 생성 후 바로 파괴되기 때문에 __tabCount가 항상 0에 머무른다. 그러면 로그에 탭이 찍히지 않는다.

예시: 함수 시작 부분마다 FUNCNAME()을 써서 호출 깊이와 순서를 확인

Comments