[잡담] 하늘아래 새로운 것은 없군요. log4cxx는 2008-04-03 이 마지막이지만 제가 원하는거 다 있네요.
log4cxx 2008-04-03 이 마지막이지만 너무 훌륭하네요.
기본적으로 제공하는 LOG4CXX_INFO 류는 고정 문자열이라
가변 문자열을 넣고 싶은데 찾아봐도 없어서 함수를 새로 만들었는데,
혹시나 뻘짓한것 아닌가 해서 찾아 열심히 열심히 찾아보니,
하늘아래 새로운것은 없군요.
log4cxx에 대해서 가장 좋은 정보를 주는 사이트로 http://joygram.org 강추합니다.
참고 url : http://joygram.org/wiki/doku.php?id=log4cxxsample1
--- 인용 ----
가변인자를 받고 싶다면...
#define __LOG4CXX_WRAPPER(level, log, ...) \
{ \
if (log->isEnabledFor(level) ) { \
char msg[1024]; \
snprintf(msg, 1024, __VA_ARGS__); \
LOG4CXX_LOG(log, level, msg) \
} \
}
#define LOGGER_FATAL(log, ...) \
__LOG4CXX_WRAPPER(log4cxx::Level::FATAL, log, __VA_ARGS__)
#define LOGGER_ERROR(log, ...) \
__LOG4CXX_WRAPPER(log4cxx::Level::ERROR, log, __VA_ARGS__)
#define LOGGER_WARN(log, ...) \
__LOG4CXX_WRAPPER(log4cxx::Level::WARN, log, __VA_ARGS__)
#define LOGGER_INFO(log, ...) \
__LOG4CXX_WRAPPER(log4cxx::Level::INFO, log, __VA_ARGS__)
#define LOGGER_DEBUG(log, ...) \
__LOG4CXX_WRAPPER(log4cxx::Level::DEBUG, log, __VA_ARGS__)
// 사용방법은...
LOGGER_FATAL(log, "fatal output...%s,%d,%f", "hoge", 123, 456.78);
LOGGER_ERROR(log, "error output...%s,%d,%f", "hoge", 123, 456.78);
LOGGER_WARN (log, "warn output...%s,%d,%f", "hoge", 123, 456.78);
LOGGER_INFO (log, "info output...%s,%d,%f", "hoge", 123, 456.78);
LOGGER_DEBUG(log, "debug output...%s,%d,%f", "hoge", 123, 456.78);
만약 없다면 구글링을 잘못 했을 뿐...
만약 없다면 구글링을 잘못 했을 뿐...
------식은이 처------
길이 끝나는 저기엔 아무 것도 없어요. 희망이고 나발이고 아무 것도 없어.
저 매크로에 정말 원하시는게 다 있는것지는
저 매크로에 정말 원하시는게 다 있는것지는 의문이가네요.
저런 가변인자로 로그용 매크로를 설정하는 것은 오래전부터 널리 쓰이는 방식입니다.
http://gcc.gnu.org/onlinedocs/gcc-3.2.3/cpp/Variadic-Macros.html
위의 주소는 gcc 문서 중, __VA_ARGS__ 에 대한 설명인데,
저 문서에도 잘 설명되어 있듯이
#define eeprint(format, ...) func(stderr, format, __VA_ARGS__)
저런식의 매크로는 문제가 있습니다. 가변인자 아무것도 없이
그냥 문자열만 출력하려면 컴파일 에러가 납니다.
eprintf("success!\n", );
==> fprintf(stderr, "success!\n", );
__LOG4CXX_WRAPPER() 또한 마찬가지입니다. 적어도 gcc 에서는
LOGGER_FATAL( "foo" )
LOGGER_ERROR( "foo" )
...
모두 컴파일 에러가 납니다.
해결 방법은 저 gcc 문서에 다 잘 나와있으니 읽어보시고 참고하세요.
그리고 이건 취향 차이일 수도 있지만
대부분
#define my_print( ... )
{
}
보다는
#define my_print( ... )
do
{
....
} while( 0 )
을 많이들 사용합니다.
사실 이유는 저도 잘 모르겠네요. :P
둘 다, C89, c99, C++98 문법안에서 큰 문제가 없어보입니다.
또한, 한 가지 또 다른 팁은
LOGGER_FATAL()
LOGGER_DEBUG()
같은 로그 함수/매크로 에서는
해당 로그 statement가 위치한 소스 파일이름과 라인넘버를 출력하게끔 설정하는 경우가 많습니다.
그래서, 로그만 보면
어느 소스파일의 어느 라인이 속한 로직에서 에러가 났는지 바로 알수있기 때문에 디버깅시 용이합니다.
좀 욕심을 부리자면
LOGGER_FATAL() 같이 심각한 에러가 났을 때 출력하는 로그 함수/매크로 같은 경우는, 로그 출력에
해당 소스파일이름과 라인넘버 뿐만이 아니라 그 당시의 콜 스택까지 뿌려주게끔 구현할수 있습니다.
물론, 이 경우 단지 저렇게 몇줄 짜리 매크로만은 안되고, 좀 귀찮은 코딩을 해야하지만, 이런 정보들은
서버 프로그램에게는 중요한 부분이 될 수 있습니다.
예전에 - 5년도 더 전에 - Samba를 가지고 장난치다가 samba가 SIG_SEGV를 받고 죽게 되면
죽기전에 로그로 당시의 콜 스택을 뿌려주고 죽었던...(아주 착한 녀석입니다.) 그런 기억이 나네요.
좋은 글 감사합니다.
좋은 글 감사합니다.
모든지 처음 보는 저에게 "오래전부터 널리 쓰이는 방식입니다" 문구는
왠지 제 맘을 아프게 하는군요.
하지만 _VA_ARGS__ 주의 사항과
콜스택 같은 개선사항을 말씀해 주셔서 감사합니다.
do {} while (0) 는 취향차이라기 보다는
세미콜론(;)에의한 컴파일 오류를 방지하기 위한 방법입니다.
위 예의 my_print 매크로를 다음과 같이 사용한다면,
"do {} while (0)" 가 아닌 경우, dangling else 로 인해 컴파일 에러가 납니다.
더 자세한 내용은 아래 링크에..
http://stackoverflow.com/questions/1067226/c-multi-line-macro-do-while0-vs-scope-block?tab=active#tab-top
감사합니다.
이제야 명확하게 이해가 가네요. 앞으로 { } while( 0 )로 변경해야겠군요.
모르고 이런 에러 당하면 저 같은 초보는 "뚫어져라 모니터야!" 라고 주문을 외우겠군요.
좋은 정보 감사합니다.
으음.. 콜스택 뿌려주는게 가능한가요?
으음.. 콜스택 뿌려주는게 가능한가요?
가변인자는 대부분 알고 있었던 내용이긴 한데, 콜스택을 뿌려주는 내용은 신기하네요.
관련 자료를 확인할수 있는 방법이 있을까요? 음... 검색어라도.. : )
검색어는....그냥 C/C++ print call
검색어는....그냥 C/C++ print call stack
으로 구글링 하시면 자료가 많이 나오고요
그중에 stackoverflow에 올라온 같은 질문이 있네요.
http://stackoverflow.com/questions/3899870/print-call-stack-in-c-or-c
참고하시길.
감사합니다.
감사합니다. (^^)