How To Use Google Logging Library(glog)
Introduction
Google glog는 어플리케이션 수준의 로깅을 구현한 라이브러리이다. 이 라이브러리는 C++ 스타일의 스트림과 다양한 헬퍼 매크로들에 기반한 로깅 API 들을 제공한다. LOG(<특정 severity level>) 로 간단하게 스트리밍해서 메시지를 남길 수 있다. 예를 들면,#include <glog/glogging.h>
int main(int argc, char* argv[]) {
// Initialize Google's logging library.
google::InitGoogleLogging(argv[0]);
// ....
LOG(INFO) << "Found " << num_cookies << " Cookies";
}
Severity Level
다음 severity level 들 중에 하나를 명시할 수 있다(severity 증가 순서대로) :INFO, WARNING, ERROR, FATAL
. FATAL 메시지를 남기면 프로그램을 종료시킨다(메시지가 출력된 뒤에). 주어진 severity 의 메시지들은 해당 severity 로그 파일에 남길 뿐만 아니라, 자신보다 낮은 severity 레벨의 파일들에도 전부 남긴다. 예를 들면, FATAL 단계의 메시지는 FATAL, ERROR, WARNING, INFO 단계의 파일들에 로그를 남기게 된다.DFATAL 단계는 디버그 모드에서 FATAL 에러를 남긴다(즉, NDEBUG 매크로가 정의되지 않은 곳). 하지만 자동으로 ERROR 단계로 낮추어서 프로그램이 종료되는 것을 피할 수 있다.
특별히 명시된 것이 없다면, glog는 파일을 "/tmp/<program name>.<hostname>.<user name>.log.<severity level>.<date>.<time>.<pid>" 이름으로 남긴다(예를 들면, "/tmp/hello_world.example.com.hamaji.log.INFO.20080709-222411.10474"). 기본적으로, glog는 ERROR 이나 FATAL 단계의 로그 메시지들을 로그 파일 이외에도 standard error(stderr) 로 복사를 한다.
Setting Flags
몇몇 플래그들은 glog의 출력 작용에 영향을 끼친다. 당신의 머신에 Google gflags 라이브러리가 설치되어 있다면, 커맨드 라인에 플래그를 전달하도록 하는 configure 스크립트(이 스크립트에 대한 자세한 내용은 패키지에 있는 INSTALL 파일을 보라)가 자동으로 감지하고 사용한다. 예를 들면, --logtostderr 플래그를 켜길 원한다면, 다음의 커맨드 라인으로 어플리케이션을 실행하면 된다../your_application --logtostderr=1
GLOG_logtostderr=1 ./your_application
logtostderr (bool, default=false)
로그 파일이 아닌 stderr 로 메시지를 남긴다.NOTE: 플래그에 true 를 의미하는 1, true, yes 를 사용해서 설정할 수 있다(대소문자 구분 없음). 그리고 false 에 대해서는 0, false, no 를 사용해서 설정할 수 있다.
stderrthreshold(int, default=2, which is ERROR)
지정한 레벨과 그 위의 레벨들의 로그 메시지들을 로그 파일 외에 stderr 로 복사를 한다. severity 레벨들 INFO, WARNING, ERROR, FATAL 은 0, 1, 2, 3 에 대응된다.minloglevel(int, default=0, which is INFO)
지정한 레벨과 그 위의 레벨들의 메시지를 남긴다. severity 레벨들 INFO, WARNING, ERROR, FATAL 은 0, 1, 2, 3 에 대응된다.log_dir(string, default="")
값이 명시되면, 로그파일들은 기본 디렉토리 대신에 이 디렉토리에 남겨진다.SetLogDestination(LogSeverity severity, const char* base_filename)
이다. 다음과 같이 사용한다.google::SetLogDestination(google::GLOG_INFO, "./Log.");
v(int, default=0)
VLOG(m) 메시지들을 보여줄 때, m에 대해서 이 플래그의 값보다 같거나 낮은 경우에 대해서만 보여준다. --vmodule 에 의해서 오버라이드 될 수 있다. 자세한 내용은 the section about verbose logging 을 참고.vmodule(string, default="")
Per-module verbose level. 이 인자는 콤마로 구분되는 <module name>=<log level> 의 리스트를 포함하고 있어야 한다. <module name> 은 파일 이름 긱반으로 매치 시키는 glog 패턴이다(예를 들면, 'gfs' 로 시작되는 이름을 가진 모든 모듈들에 대해서는 gfs* 사용). <log level> 은 --v 에 의해서 주어지는 값을 오버라이드 한다. 자세한 내용은 the section about verbose logging 을 참고.logging.cc 에는 몇몇 다른 플래그들도 정의되어 있다. 모든 플래그의 리스트를 보고 싶다면, "DEFINE_" 로 소스 코드를 검색해 보면 된다.
Conditional / Occasional Logging
때때로, 특정 상태에서만 메시지를 남기고 싶을 때가 있을 것이다. 특정 상태에 대해서 로그를 남기기 위해서 다음의 매크로를 사용할 수 있다.LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookies";
다음과 같이 상태에 따라서 그리고 임의로 남기도록 조합형태로 사용할 수 있다.
LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER << "th big cookies";
LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
Debug Mode Support
"debug mode" 로깅 매크로는 디버그 모드에서만 효과가 있고 디버그 모드가 아닐 때는 컴파일에서 제외가 된다. 출시가 되는 어플리케이션에서 지나친 로깅으로 느려지는 것을 피하려면 이 매크로를 사용하면 된다.DLOG(INFO) << "Found cookies";
DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookies";
CHECK Macros
가능한 빠르게 에러를 발견해야 하는 프로그램에서 기대했던 상태를 체크하는 것은 좋은 기능이다. CHECK 매크로는 상태를 만나지 못했을 때, 어플리케이션을 중단하는 기능을 제공한다. 이 매크로는 Standard C 라이브러리에 정의되어 있는 assert 매크로와 유사하다.CHECK 는 상태가 true 가 아닐 때 어플리케이션을 중단한다. assert 와는 다르게, NDEBUG 에 의해서 컨트롤되지 않기 때문에 컴파일 모드를 무시하고 CHECK 는 실행된다. 그러므로, 다음의 예에 있는 fp-Write(x)는 항상 실행된다:
CHECK(fp->Write(x) == 4) << "Write failed!";
다음과 같이 에러 메시지를 붙일 수 있다:
CHECK_NE(1, 2) << ": The world must be ending!";
CHECK_EQ(string("abc")[1], 'b');
CHECK_EQ(some_ptr, static_cast<SomeType*>(NULL));
CHECK_NOTNULL(some_ptr);
some_ptr->DoSomething();
struct S {
S(Something* ptr) : ptr_(CHECK_NOTNULL(ptr)) {}
Something* ptr_;
};
이러한 것 때문에 C++ 스트림 처럼 이 매크로를 사용할 수 없을 것이다. 어플리케이션이 중단 되기 전에 커스텀 메시지를 남기고 싶다면 위에서 언급한 CHECK_EQ 를 사용해 주기 바란다.
C 스트링(char*)를 비교한다면, 대소문자를 구분하는 매크로가 있고 구분하지 않는 매크로도 있다 -
CHECK_STREQ , CHECK_STRNE, CHECK_STRCASEEQ, CHECK_STRCASENE
. CASE 버전이 대소문자 구분을 하는 것이다. 이 매크로에는 NULL 포인터도 안전하게 전달할 수 있다. 이 매크로들은 NULL 과 NULL 이 아닌 스트링을 다른 것으로 다룬다. 둘다 NULL 일 경우에는 동일한 것으로 간주된다.양쪽 인자들이 현재의 전체 표현이 끝나는 지점에서 파괴되는 임시 스트링일 수도 있다(예를 들면, CHECK_STREQ(Foo().c_str(), Bar().c_str()) 에서 Foo와 Bar가 리턴하는 C++의 std::string)
CHECK_DOUBLE_EQ 매크로는 약간의 오차를 허용하면서 두 개의 실수형 값들의 등식을 체크한다. CHECK_NEAR 는 세 번째 실수형 인자를 받아들이고, 세 번째 인자는 허용되는 오차를 명시한다.
Verbose Logging
어려운 버그들을 추적하고 있을 때, 로그 메시지는 매우 유용하다. 하지만, 일반적인 개발에서는 너무 장황한 메시지들을 무시하고 싶기도 할 것이다. 장황한 로그 같은 경우에, glog는 VLOG 매크로를 제공하고 있는데 이 매크로는 사용자만의 수치적 로깅 레벨을 정의할 수 있게 해준다.--v 커맨드 라인 옵션은 어떤 verbose message 들이 남겨질지를 컨트롤한다:
VLOG(1) << "I'm printed when you run the program with --v=1 or higher";
VLOG(2) << "I'm printed when you run the program with --v=2 or higher";
Verbose logging은 각각의 모듈 기반으로 커맨드 라인을 사용해서 컨트롤 된다.
--vmodule=mapreduce=2,file=1,gfs*=3 --v=0
- a. mapreduce.{h,cc} 에서 발생되는 낮은 단계의 메시지들과 VLOG(2)를 출력한다.
- b. file.{h,cc} 에서 발생되는 낮은 단계의 메시지들과 VLOG(1)을 출력한다.
- c. 접두어가 gfs 인 파일들로부터 발생되는 낮은 단계의 메시지들과 VLOG(3)을 출력한다.
- d. 어디에서든 발생되는 낮은 단계의 메시지들과 VLOG(0)을 출력한다.
VLOG_IS_ON(n) "verbose level" 컨디션 매크로도 있다. 이 매크로는 --v 가 n 과 같거나 그 이상일 때 true를 리턴한다. 다음과 같이 사용된다.
if (VLOG_IS_ON(2)) {
// do some logging preparation and logging
// that can't be accomplished with just VLOG(2) << .... ;
}
VLOG_IF(1, (size > 1024)) << "I'm printed when size is more than 1024 and when you run the program with --v=1 or more";
VLOG_EVERY_N(1, 10) << "I'm printed every 10th occurrence, and when you run the program with --v=1 or more. Present occurence is << google::COUNTER;
VOLOG_IF_EVERY_N(1, (size > 1024), 10)
<< "I'm printed on every 10th occurence of case when size is more than 1024, when you run the program with --v=1 or more. Present occurence is " << google::COUNTER;
Failure Signal Handler
라이브러리는 프로그램이 SIGSEGV 같은 특정 시그널에서 크래시 되었을 때 유용한 정보를 덤프하는 편리한 시그널 핸들러를 제공한다. 시그널 핸들러는 google::InstallFailureSignalHandler() 에 의해서 설치된다. 다음은 시그널 핸들러로부터의 출력 예제이다.기본적으로, 시그널 핸들러는 standard error로 failure dump를 작성한다. InstallFailureWriter() 를 이용해서 도착지를 커스터마이징할 수 있다.*** Aborted at 1225095260 (unix time) try "date -d @1225095260" if you are using GNU date *** *** SIGSEGV (@0x0) received by PID 17711 (TID 0x7f893090a6f0) from PID 0; stack trace: *** PC: @ 0x412eb1 TestWaitingLogSink::send() @ 0x7f892fb417d0 (unknown) @ 0x412eb1 TestWaitingLogSink::send() @ 0x7f89304f7f06 google::LogMessage::SendToLog() @ 0x7f89304f35af google::LogMessage::Flush() @ 0x7f89304f3739 google::LogMessage::~LogMessage() @ 0x408cf4 TestLogSinkWaitTillSent() @ 0x4115de main @ 0x7f892f7ef1c4 (unknown) @ 0x4046f9 (unknown)
Miscellaneous Notes
Performance of Messages
glog에 의해서 제공되는 상태에 대한 로깅 매크로들(예를 들면, CHECK, LOG_IF, VLOG, ...)은 주의 깊게 구현되었고 상태가 false 일 때 right hand side expression을 실행하지 않는다. 그래서 다음과 같은 체크는 어플리케이션의 성능을 희생하지 않을 것이다.CHECK(obj.ok) << obj.CreatePrettyFormattedStringButVerySlow();
User-defined Failure Function
FATAL severity 레벨 메시지들이나 만족되지 않은 CHECK 컨디션은 프로그램을 종료시킨다. InstallFailureFunction 을 사용해서 종료 시키는 행동을 바꿀 수 있다.void YourFailureFunction() {
// Reports something....
exit(1);
}
int main(int argc, char* argv[]) {
google::InstallFailureFunction(&YourFailureFunction);
}
Raw Logging
<glog/raw_logging.h> 헤더 파일은 메모리 할당이나 메모리 락을 사용하지 않는 쓰레드 세이프 로깅에 대해서 사용될 수 있다. 그러므로, 이 헤더 파일에 정의된 매크로들은 low-level 메모리 할당과 동기화 코드에서 사용될 수 있다. 자세한 내용은 src/glog/raw_logging.h 를 확인해 보라.Google Style perror()
PLOG() 와 PLOG_IF(), PCHECK() 는 errno 의 현재 상태를 기술한 내용에 출력 라인을 붙인 형태의 LOG*, CHECK 처럼 행동한다. 예를 들면,PCHECK(write(1, NULL, 2) >= 0) << "Write NULL failed";
F825 185142 test.cc:22] Check failed: write(1, NULL, 2) >= 0 Write NULL failed: Bad address [14]
Syslog
SYSLOG, SYSLOG_IF, SYSLOG_EVERY_N 매크로들도 사용할 수 있다. 이 매크로들은 일반 로그 메시지에 syslog를 더해서 출력을 한다. syslog를 출력하는 것은 과감하게 성능에 영향을 줄 수 있으며, 특히 syslog가 리모트 로깅이 설정되어 있다면 더욱더 그렇다. 이 매크로를 사용하기 전에 syslog에 의한 영향에 대해서 이해를 하고 있어야 한다. 일반적으로, 이 매크로들은 적게 사용하는 것이 현명하다.Strip Logging Messages
로그 메시지에 사용되는 스트링들은 실행 파일의 사이즈를 증가시킬 수 있으며 프라이버시 문제를 줄 수 있다. 그러므로 GOOGLE_STRIP_LOG 매크로를 사용해서 특정 severity 레벨 하위에 있는 모든 스트링을 제거하도록 glog 에게 지시해야 한다.어플리케이션이 다음과 같은 코드를 가지고 있다면:
#define GOOGLE_STRIP_LOG 1 // this must go before the #include!
#include <glog/logging.h>
Notes for Windows Users
Google 의 glog는 ERROR 라는 severity 레벨을 정의하고 있고 ERROR는 windows.h 에도 정의되어 있다. glog/logging.h 를 포함하기 전에GLOG_NO_ABBREVIATED_SEVERITIES를 정의해서 glog가 INFO, WARNING, ERROR, FATAL을 정의하지 않도록 만들 수도 있다. 이 매크로를 사용하면서, 여전히 iostream 을 사용할 수 있다.#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <windows.h>
#include <glog/logging.h>
// ...
LOG(ERROR) << "This should work";
LOG_IF(ERROR, x > y) << "This should be also OK";
windows.h 에 정의되어 있는 ERROR 가 필요하지 않다면, 종종 작동하지 않는 몇 가지 대안이 있다.#define GLOG_NO_ABBREVIATED_SEVERITIES #include <windows.h> #include <glog/logging.h> // ... // This won't work. // google::FlushLogFiles(google::ERROR); // Use this instead. google::FlushLogFiles(google::GLOG_ERROR);
- #include <windows.h> 전에 #define WIN32_LEAN_AND_MEAN 이나 NOGDI
- #include <windows.h> 다음에 #undef ERROR
댓글 없음:
댓글 쓰기