glog는 Google에서 개발한 강력한 로깅 라이브러리로, 대규모 C 프로젝트에서 효율적인 로깅 관리를 돕습니다. C 언어는 기본적으로 강력한 로깅 기능을 제공하지 않으므로, 개발자들은 printf()
같은 기본 출력 함수나 syslog
같은 시스템 로깅을 활용해야 합니다. 하지만 이러한 방법은 대량의 로그를 효율적으로 관리하는 데 한계가 있습니다.
glog는 다양한 로그 레벨(INFO, WARNING, ERROR, FATAL)을 제공하며, 자동 로그 파일 회전, 멀티스레딩 지원, 성능 최적화 기능을 갖추고 있어 대규모 애플리케이션에서도 안정적인 로깅 환경을 구축할 수 있습니다. 또한, 로그 파일을 자동으로 저장하고 필요한 경우 콘솔에 출력하는 기능도 제공하여 개발자가 보다 편리하게 로깅을 활용할 수 있습니다.
본 기사에서는 glog의 기본 사용법부터 설치 방법, 성능 최적화, 멀티스레딩 환경에서의 로깅 관리까지 다양한 주제를 다룹니다. 이를 통해 C 프로젝트에서 glog를 활용하여 보다 효율적으로 로그를 관리하는 방법을 익힐 수 있습니다.
glog란 무엇인가?
glog(Google Logging Library)는 Google에서 개발한 오픈소스 로깅 라이브러리로, C 및 C++ 프로젝트에서 강력한 로깅 기능을 제공합니다. 기존 printf()
기반 디버깅보다 훨씬 효율적이며, 다양한 로그 레벨 지원, 자동 로그 파일 저장, 멀티스레딩 환경 지원 등의 기능을 제공합니다.
glog의 주요 특징
glog는 대규모 애플리케이션을 위한 로깅 시스템으로 다음과 같은 핵심 기능을 제공합니다.
- 로그 레벨 지원
LOG(INFO)
,LOG(WARNING)
,LOG(ERROR)
,LOG(FATAL)
을 제공하여 로그의 중요도를 구분할 수 있습니다.
- 자동 로그 파일 관리
- 로그를 파일로 저장하고, 일정 크기가 넘으면 자동으로 회전(logging rotation)하는 기능을 지원합니다.
- 스택 트레이스(Stack Trace) 출력
LOG(FATAL)
을 사용할 경우 프로그램이 종료되면서 스택 트레이스를 출력하여 디버깅을 쉽게 할 수 있습니다.
- 멀티스레딩 지원
- 다중 스레드 환경에서도 안전하게 로그를 출력할 수 있도록 설계되었습니다.
- 출력 옵션 커스터마이징
- 로그를 파일뿐만 아니라 표준 출력(콘솔)이나 원격 서버로 전송할 수도 있습니다.
glog와 기존 로깅 방식 비교
방식 | 특징 및 장점 | 단점 |
---|---|---|
printf() | 간단하게 출력 가능 | 로그 관리 어려움, 멀티스레딩에서 충돌 가능 |
syslog() | 시스템 레벨 로깅 가능 | 설정이 복잡하고, 별도의 로깅 파일이 필요 |
glog | 다양한 로그 레벨 지원, 자동 로그 파일 저장, 성능 최적화 | 별도 설치 필요 |
glog 사용 사례
glog는 구글 내부에서 사용되는 수많은 서비스에서 활용되며, 대규모 분산 시스템, 머신러닝 애플리케이션, 네트워크 서버 등에서 널리 사용됩니다. 특히, 장기적으로 관리해야 하는 대규모 프로젝트에서 강력한 로깅 시스템이 필요할 때 유용합니다.
다음 장에서는 glog를 C 프로젝트에 설치하고 설정하는 방법을 자세히 설명하겠습니다.
glog 설치 및 설정
glog를 C 프로젝트에서 사용하려면 먼저 라이브러리를 설치하고 환경을 설정해야 합니다. glog는 Linux, macOS, Windows에서 모두 사용할 수 있으며, CMake를 이용한 빌드 환경을 지원합니다.
glog 설치 방법
1. 패키지 관리자를 이용한 설치
대부분의 Linux 배포판과 macOS에서는 패키지 관리자를 이용해 쉽게 설치할 수 있습니다.
Ubuntu 및 Debian 계열:
sudo apt update
sudo apt install libgoogle-glog-dev
CentOS 및 RHEL 계열:
sudo yum install glog-devel
macOS(Homebrew 사용):
brew install glog
2. 소스 코드로 빌드 및 설치
패키지 관리자가 지원되지 않거나 최신 버전이 필요할 경우, glog의 공식 GitHub 저장소에서 소스 코드를 다운로드하여 직접 빌드할 수 있습니다.
git clone https://github.com/google/glog.git
cd glog
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local
make -j$(nproc)
sudo make install
C 프로젝트에서 glog 설정하기
glog를 C 프로젝트에서 사용하려면 CMakeLists.txt
파일에 다음과 같이 추가해야 합니다.
find_package(glog REQUIRED)
target_link_libraries(my_project PRIVATE glog::glog)
또는, 직접 컴파일할 경우 다음과 같이 링킹해야 합니다.
gcc my_program.c -lglog -o my_program
환경 변수 설정
glog는 로그 파일을 저장할 디렉터리를 설정해야 합니다. 환경 변수를 설정하여 로그 파일이 저장될 위치를 지정할 수 있습니다.
export GLOG_log_dir=/var/log/my_project
mkdir -p $GLOG_log_dir
또한, 실행 시 로그 파일을 특정 디렉터리에 저장하려면 프로그램 실행 전에 FLAGS_log_dir
값을 설정할 수 있습니다.
#include <glog/logging.h>
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
FLAGS_log_dir = "/var/log/my_project";
LOG(INFO) << "glog is set up!";
return 0;
}
이제 glog를 C 프로젝트에서 사용할 준비가 완료되었습니다. 다음 장에서는 기본적인 glog 사용법을 설명하겠습니다.
기본적인 glog 사용법
glog는 다양한 로그 레벨과 기능을 제공하며, 이를 활용하면 효율적인 로깅 시스템을 구축할 수 있습니다. 이 장에서는 glog의 기본적인 사용법을 살펴보겠습니다.
glog 초기화 및 종료
glog를 사용하기 전에 반드시 초기화를 수행해야 합니다. 프로그램 시작 시 google::InitGoogleLogging(argv[0])
을 호출하고, 종료 시 google::ShutdownGoogleLogging()
을 호출하는 것이 일반적인 패턴입니다.
#include <glog/logging.h>
int main(int argc, char* argv[]) {
// glog 초기화
google::InitGoogleLogging(argv[0]);
// 기본적인 로그 출력
LOG(INFO) << "이것은 정보 로그입니다.";
LOG(WARNING) << "이것은 경고 로그입니다.";
LOG(ERROR) << "이것은 오류 로그입니다.";
// 프로그램 종료 전에 glog 정리
google::ShutdownGoogleLogging();
return 0;
}
위 코드를 실행하면, 로그가 콘솔과 로그 파일에 저장됩니다.
로그 레벨
glog는 총 4가지 로그 레벨을 제공합니다.
로그 레벨 | 설명 |
---|---|
LOG(INFO) | 일반적인 정보 메시지 |
LOG(WARNING) | 경고 메시지, 심각한 문제는 아니지만 주의 필요 |
LOG(ERROR) | 오류 메시지, 프로그램이 정상적으로 동작하지 않을 가능성이 있음 |
LOG(FATAL) | 치명적인 오류 발생, 프로그램이 즉시 종료됨 |
예제 코드:
LOG(INFO) << "이것은 INFO 로그입니다.";
LOG(WARNING) << "이것은 WARNING 로그입니다.";
LOG(ERROR) << "이것은 ERROR 로그입니다.";
LOG(FATAL) << "이것은 FATAL 로그이며 프로그램이 종료됩니다.";
LOG(FATAL)
을 호출하면 프로그램이 즉시 종료되며, 종료 직전까지의 스택 트레이스가 출력됩니다.
조건부 로깅
특정 조건이 만족될 때만 로그를 출력하고 싶다면 다음과 같이 사용할 수 있습니다.
int value = 10;
LOG_IF(INFO, value > 5) << "value가 5보다 큽니다: " << value;
또한, 반복문에서 일정 횟수마다 로그를 출력하고 싶다면 LOG_EVERY_N
을 사용할 수 있습니다.
for (int i = 0; i < 100; i++) {
LOG_EVERY_N(INFO, 10) << "이 메시지는 10번마다 한 번씩 출력됩니다. 현재 카운트: " << i;
}
디버깅을 위한 DLOG
디버깅할 때만 로그를 출력하고 싶은 경우, DLOG()
를 사용할 수 있습니다.
이 로그는 디버그 모드(NDEBUG
가 정의되지 않은 경우)에만 출력됩니다.
DLOG(INFO) << "디버깅 전용 로그 메시지입니다.";
glog 기본 사용법 요약
google::InitGoogleLogging(argv[0])
을 호출하여 초기화LOG(INFO)
,LOG(WARNING)
,LOG(ERROR)
,LOG(FATAL)
을 사용하여 로그 출력LOG_IF()
,LOG_EVERY_N()
을 활용하여 조건부 로깅 적용google::ShutdownGoogleLogging();
을 호출하여 종료
다음 장에서는 로그 파일 관리와 출력 설정 방법에 대해 설명하겠습니다.
로그 파일 관리와 출력 설정
glog는 기본적으로 로그 파일을 자동으로 저장하며, 개발자가 필요에 따라 출력 경로와 형식을 설정할 수 있습니다. 이 장에서는 로그 파일 관리 및 출력 설정 방법을 설명합니다.
기본적인 로그 파일 저장 방식
glog는 FLAGS_log_dir
변수를 설정하면 로그를 특정 디렉터리에 자동 저장합니다.
#include <glog/logging.h>
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
// 로그 파일 저장 디렉터리 설정
FLAGS_log_dir = "/var/log/my_project";
LOG(INFO) << "이것은 로그 파일에 저장됩니다.";
google::ShutdownGoogleLogging();
return 0;
}
위 코드를 실행하면 /var/log/my_project
경로에 로그 파일이 생성됩니다.
로그 파일 이름 형식
glog는 기본적으로 다음과 같은 형식으로 로그 파일을 저장합니다.
<log_dir>/<프로그램명>.<호스트명>.<유저ID>.<날짜>.<시간>.<로그레벨>.log
예를 들어, 실행 파일이 my_app
일 경우 로그 파일 이름은 다음과 같습니다.
/var/log/my_project/my_app.hostname.1234.20250129-120000.INFO.log
로그 파일 회전 및 크기 제한
glog는 로그 파일이 일정 크기를 초과하면 자동으로 새로운 파일을 생성합니다. 기본값은 1GB이며, 필요에 따라 변경할 수 있습니다.
FLAGS_max_log_size = 100; // 로그 파일 최대 크기(단위: MB)
FLAGS_stop_logging_if_full_disk = true; // 디스크가 가득 차면 로깅 중단
콘솔과 로그 파일 동시 출력
기본적으로 glog는 로그 파일만 생성하고 콘솔에는 출력하지 않습니다.
콘솔에서도 로그를 확인하려면 FLAGS_alsologtostderr
옵션을 활성화해야 합니다.
FLAGS_alsologtostderr = true; // 로그를 stderr에도 출력
또는 특정 로그 레벨 이상만 콘솔에 출력하고 싶다면 FLAGS_stderrthreshold
를 설정합니다.
FLAGS_stderrthreshold = google::ERROR; // ERROR 이상만 콘솔 출력
로그 파일 형식 커스터마이징
로그 메시지의 형식을 변경하고 싶다면 FLAGS_log_prefix
와 FLAGS_logtostderr
을 조정할 수 있습니다.
FLAGS_log_prefix = false; // 로그 메시지에서 기본 prefix 제거
FLAGS_logtostderr = true; // stderr로만 로그 출력
로그 파일 관리 예제 코드
다음은 로그 파일 디렉터리 설정, 크기 제한, 콘솔 출력 활성화 등의 설정을 포함한 예제입니다.
#include <glog/logging.h>
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
FLAGS_log_dir = "/var/log/my_project";
FLAGS_max_log_size = 50; // 50MB 크기를 초과하면 새로운 파일 생성
FLAGS_alsologtostderr = true; // 콘솔에도 로그 출력
LOG(INFO) << "로그 파일과 콘솔에 출력됩니다.";
LOG(ERROR) << "이것은 ERROR 로그입니다.";
google::ShutdownGoogleLogging();
return 0;
}
요약
FLAGS_log_dir
을 사용하여 로그 파일 저장 경로 설정- 기본적으로
<프로그램명>.<날짜>.<로그레벨>.log
형식으로 로그 저장 FLAGS_max_log_size
를 사용하여 로그 파일 크기 제한 가능FLAGS_alsologtostderr
를 설정하면 콘솔과 로그 파일에 동시에 출력FLAGS_stderrthreshold
를 사용하면 특정 레벨 이상의 로그만 콘솔에 출력 가능
다음 장에서는 다양한 로그 레벨 활용법에 대해 설명하겠습니다.
다양한 로그 레벨 활용법
glog는 다양한 로그 레벨(INFO, WARNING, ERROR, FATAL)을 제공하며, 상황에 맞게 적절한 로그 레벨을 사용하면 효율적인 디버깅과 문제 해결이 가능합니다. 이 장에서는 각 로그 레벨의 의미와 사용법을 살펴보겠습니다.
로그 레벨 개요
glog는 다음과 같은 네 가지 로그 레벨을 제공합니다.
로그 레벨 | 설명 | 사용 예시 |
---|---|---|
LOG(INFO) | 일반적인 실행 정보 | 시스템 상태, 주요 이벤트 기록 |
LOG(WARNING) | 주의가 필요한 상황 | 비정상적인 입력, 잠재적 문제 |
LOG(ERROR) | 오류 발생 | 기능이 실패했지만 계속 실행 가능 |
LOG(FATAL) | 치명적 오류 | 프로그램 즉시 종료 |
로그 레벨별 예제 코드
다음 코드는 각 로그 레벨을 사용하는 예제입니다.
#include <glog/logging.h>
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
LOG(INFO) << "서버가 정상적으로 실행되었습니다.";
LOG(WARNING) << "디스크 공간이 부족합니다. (사용량 90%)";
LOG(ERROR) << "데이터베이스 연결에 실패했습니다.";
// FATAL 로그는 프로그램을 즉시 종료함
LOG(FATAL) << "메모리 부족으로 프로그램을 종료합니다.";
google::ShutdownGoogleLogging();
return 0;
}
위 코드를 실행하면, LOG(FATAL)
이후 프로그램이 즉시 종료되며, 스택 트레이스를 출력합니다.
조건부 로그 출력
특정 조건을 만족할 때만 로그를 출력하려면 LOG_IF
를 사용할 수 있습니다.
int error_count = 3;
LOG_IF(ERROR, error_count > 2) << "오류가 2개 이상 발생했습니다.";
또한, LOG_EVERY_N
을 사용하면 반복문에서 일정 횟수마다 로그를 출력할 수 있습니다.
for (int i = 0; i < 100; i++) {
LOG_EVERY_N(INFO, 10) << "이 메시지는 10번째마다 출력됩니다. 현재: " << i;
}
디버깅을 위한 DLOG
DLOG()
는 디버그 모드에서만 출력되는 로그입니다.NDEBUG
가 정의된 경우(#define NDEBUG
), DLOG()
는 비활성화됩니다.
DLOG(INFO) << "디버깅 전용 로그입니다.";
특정 로그 레벨 이상의 로그만 출력
기본적으로 glog는 모든 로그를 기록하지만, 특정 로그 레벨 이상만 출력하도록 설정할 수도 있습니다.
FLAGS_minloglevel = google::WARNING; // WARNING 이상만 기록
FLAGS_stderrthreshold = google::ERROR; // ERROR 이상만 콘솔 출력
로그 레벨 활용 전략
LOG(INFO)
: 시스템 동작을 추적하고, 주요 이벤트를 기록할 때 사용LOG(WARNING)
: 비정상적이지만 실행 가능할 때 경고 메시지 출력LOG(ERROR)
: 오류 발생 시 기록하지만, 시스템 실행을 유지할 때 사용LOG(FATAL)
: 프로그램이 정상적으로 실행될 수 없는 치명적 오류 발생 시 사용
요약
LOG(INFO)
,LOG(WARNING)
,LOG(ERROR)
,LOG(FATAL)
로그 레벨 제공LOG_IF()
및LOG_EVERY_N()
으로 조건부 로깅 가능DLOG()
를 사용하면 디버그 모드에서만 로그 출력FLAGS_minloglevel
및FLAGS_stderrthreshold
로 특정 레벨 이상 로그만 출력 가능
다음 장에서는 성능 최적화를 위한 로깅 기법을 설명하겠습니다.
성능 최적화를 위한 로깅 기법
glog는 강력한 기능을 제공하지만, 잘못된 로깅 사용은 성능 저하를 초래할 수 있습니다. 특히, 대규모 프로젝트에서 로깅은 성능에 영향을 미칠 수 있으므로 최적화 기법을 적용하는 것이 중요합니다.
1. 불필요한 로그 줄이기
과도한 로그는 디스크 I/O 부하를 증가시키고 프로그램 실행 속도를 저하시킬 수 있습니다.FLAGS_minloglevel
을 설정하여 필요하지 않은 로그를 줄일 수 있습니다.
FLAGS_minloglevel = google::WARNING; // WARNING 이상만 기록 (INFO 무시)
이 설정을 적용하면 LOG(INFO)
로그는 기록되지 않아 성능이 향상됩니다.
2. LOG_EVERY_N()으로 중복 로그 방지
반복문에서 과도하게 로그를 출력하면 성능이 저하될 수 있습니다.LOG_EVERY_N()
을 사용하면 특정 횟수마다 한 번씩만 로그를 출력하도록 제한할 수 있습니다.
for (int i = 0; i < 1000000; i++) {
LOG_EVERY_N(INFO, 1000) << "이 메시지는 1000번마다 한 번 출력됩니다. 현재: " << i;
}
이렇게 하면 로그 파일의 크기를 줄이고, 성능 저하를 방지할 수 있습니다.
3. LOG_IF()로 조건부 로깅
불필요한 로그를 줄이려면 특정 조건을 만족할 때만 로그를 출력하는 것이 좋습니다.
int error_count = 0;
LOG_IF(WARNING, error_count > 5) << "에러가 5개 이상 발생했습니다!";
위 코드는 error_count > 5
일 때만 로그를 출력하므로 성능 오버헤드를 줄일 수 있습니다.
4. 비동기 로깅 사용
glog는 기본적으로 동기식 로깅을 수행하는데, I/O 비용이 높은 환경에서는 병목이 될 수 있습니다.
이를 해결하기 위해 별도의 스레드에서 로그를 처리하는 비동기 로깅 방식을 적용할 수 있습니다.
glog 자체적으로 비동기 로깅을 제공하지 않지만, 백그라운드 스레드와 큐를 활용하면 비동기 로깅을 구현할 수 있습니다.
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <glog/logging.h>
std::queue<std::string> logQueue;
std::mutex logMutex;
std::condition_variable logCondition;
bool stopLogging = false;
// 로그 처리 스레드
void logWorker() {
while (!stopLogging) {
std::unique_lock<std::mutex> lock(logMutex);
logCondition.wait(lock, [] { return !logQueue.empty() || stopLogging; });
while (!logQueue.empty()) {
LOG(INFO) << logQueue.front();
logQueue.pop();
}
}
}
void asyncLog(const std::string& message) {
{
std::lock_guard<std::mutex> lock(logMutex);
logQueue.push(message);
}
logCondition.notify_one();
}
위 코드는 비동기 로그 처리 스레드를 생성하여 로그 출력 성능을 개선하는 방식입니다.
5. 로그 파일 크기 관리
로그 파일이 너무 커지면 디스크 용량을 차지하고, 로딩 속도가 저하됩니다.FLAGS_max_log_size
를 설정하면 일정 크기를 초과할 경우 새로운 로그 파일을 생성합니다.
FLAGS_max_log_size = 50; // 50MB를 초과하면 새로운 로그 파일 생성
FLAGS_stop_logging_if_full_disk = true; // 디스크가 가득 차면 로깅 중단
이렇게 하면 로그 파일이 무한정 커지는 것을 방지할 수 있습니다.
6. DEBUG 로그 제거
DLOG()
를 사용하면 디버그 모드에서만 로그가 활성화되므로, 릴리즈 빌드에서는 로그가 자동으로 제거됩니다.
DLOG(INFO) << "디버그 전용 로그 (릴리즈 모드에서는 출력되지 않음)";
성능 최적화 요약
✅ 불필요한 로그 제거 (FLAGS_minloglevel
사용)
✅ LOG_EVERY_N() 사용하여 중복 로그 방지
✅ LOG_IF()를 활용한 조건부 로깅
✅ 비동기 로깅을 구현하여 성능 개선
✅ 로그 파일 크기 제한 (FLAGS_max_log_size
)
✅ DEBUG 로그 (DLOG()
)를 릴리즈 빌드에서 제거
다음 장에서는 멀티스레딩 환경에서의 로깅 관리 방법을 설명하겠습니다.
멀티스레딩 환경에서의 로깅 관리
glog는 기본적으로 멀티스레드 환경에서 안전하게 동작하도록 설계되어 있습니다. 하지만 잘못된 사용 방식이나 과도한 동기화로 인해 성능 저하가 발생할 수 있습니다. 이 장에서는 멀티스레딩 환경에서 glog를 효율적으로 활용하는 방법을 설명합니다.
1. glog의 멀티스레드 지원
glog는 내부적으로 뮤텍스(Mutex)를 사용하여 스레드 안전성을 보장합니다. 즉, 여러 개의 스레드에서 동시에 LOG()
를 호출해도 충돌 없이 동작합니다.
다음과 같이 여러 스레드에서 동시에 로그를 남길 수 있습니다.
#include <glog/logging.h>
#include <thread>
void logTask(int thread_id) {
for (int i = 0; i < 5; i++) {
LOG(INFO) << "스레드 " << thread_id << ": 로그 메시지 " << i;
}
}
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
std::thread t1(logTask, 1);
std::thread t2(logTask, 2);
std::thread t3(logTask, 3);
t1.join();
t2.join();
t3.join();
google::ShutdownGoogleLogging();
return 0;
}
위 코드를 실행하면 각 스레드가 독립적으로 로그를 기록하며, glog가 자동으로 동기화하여 충돌을 방지합니다.
2. 성능 최적화를 위한 비동기 로깅
기본적으로 glog는 로그를 즉시 파일에 기록합니다. 하지만, 멀티스레드 환경에서 동기식 파일 쓰기는 성능을 저하시킬 수 있습니다.
이를 방지하려면 비동기 로깅을 구현하여 별도의 스레드에서 로그를 처리하는 방식이 유용합니다.
#include <glog/logging.h>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
std::queue<std::string> logQueue;
std::mutex logMutex;
std::condition_variable logCondition;
bool stopLogging = false;
void logWorker() {
while (!stopLogging) {
std::unique_lock<std::mutex> lock(logMutex);
logCondition.wait(lock, [] { return !logQueue.empty() || stopLogging; });
while (!logQueue.empty()) {
LOG(INFO) << logQueue.front();
logQueue.pop();
}
}
}
void asyncLog(const std::string& message) {
{
std::lock_guard<std::mutex> lock(logMutex);
logQueue.push(message);
}
logCondition.notify_one();
}
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
std::thread logThread(logWorker);
asyncLog("비동기 로깅 예제 시작");
asyncLog("멀티스레딩 환경에서 안전한 로그 처리");
stopLogging = true;
logThread.join();
google::ShutdownGoogleLogging();
return 0;
}
✅ 비동기 로깅 방식을 적용하면 로그 기록이 병렬적으로 처리되면서 성능이 향상됩니다.
3. 스레드별 로그 파일 분리
기본적으로 모든 스레드는 같은 로그 파일을 공유합니다. 하지만, 각 스레드별로 개별적인 로그 파일을 생성하고 싶다면 FLAGS_log_filename_extension
을 활용할 수 있습니다.
FLAGS_log_filename_extension = "_thread1"; // 각 스레드별 고유한 파일 확장자 지정
이 방법을 사용하면 로그 파일이 다음과 같이 생성됩니다.
/var/log/my_project/my_app_thread1.INFO.log
/var/log/my_project/my_app_thread2.INFO.log
이렇게 하면 스레드별 로그 관리가 쉬워지고, 동기화 부담이 줄어들어 성능이 향상됩니다.
4. 특정 스레드의 로그 필터링
멀티스레드 환경에서는 특정 스레드의 로그만 보고 싶을 때가 있습니다.
이 경우 스레드 ID를 출력하여 특정 스레드의 로그만 필터링할 수 있습니다.
#include <sys/syscall.h> // gettid() 사용
#include <unistd.h>
LOG(INFO) << "Thread ID: " << syscall(SYS_gettid) << " - 메시지 출력";
위 코드를 실행하면 각 로그 메시지에 스레드 ID가 포함되므로, 특정 스레드의 로그만 추출하여 분석할 수 있습니다.
5. 멀티스레드 환경에서 로그 성능 최적화
✅ 멀티스레딩을 지원하는 glog 활용
✅ 비동기 로깅 기법 적용 (별도 스레드에서 로그 처리)
✅ 스레드별 로그 파일 생성 (FLAGS_log_filename_extension
)
✅ 특정 스레드의 로그 필터링 (스레드 ID 출력)
다음 장에서는 glog를 활용한 디버깅 및 문제 해결 방법을 설명하겠습니다.
glog를 활용한 디버깅 및 문제 해결
glog는 단순한 로깅 기능을 넘어서, 디버깅과 문제 해결을 위한 강력한 도구로 활용될 수 있습니다.
이 장에서는 효율적인 디버깅 기법, 스택 트레이스 활용, 로그 분석 방법을 설명합니다.
1. 스택 트레이스를 활용한 디버깅
glog는 LOG(FATAL)
을 호출하면 스택 트레이스를 자동으로 출력합니다.
이 기능을 활용하면 오류가 발생한 지점을 쉽게 추적할 수 있습니다.
#include <glog/logging.h>
void faultyFunction() {
LOG(FATAL) << "치명적 오류 발생! 프로그램 종료!";
}
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
faultyFunction(); // 이 함수에서 LOG(FATAL)이 호출됨
google::ShutdownGoogleLogging();
return 0;
}
실행 결과:
FATAL: main.cpp:7] 치명적 오류 발생! 프로그램 종료!
*** Check failure stack trace: ***
@ 0x5637d1c8a5f3 faultyFunction()
@ 0x5637d1c8a6d2 main
@ 0x7f4c9c89d0b3 __libc_start_main
@ 0x5637d1c8a3de _start
✅ 스택 트레이스를 활용하면 오류가 발생한 위치를 즉시 확인할 수 있습니다.
2. CHECK 매크로로 코드 검증
glog는 CHECK()
매크로를 제공하여 코드 실행 중 특정 조건을 검증할 수 있습니다.
이 기능은 assert()
와 유사하지만, 로그 출력 기능과 결합되어 디버깅이 더 쉬워집니다.
int divide(int a, int b) {
CHECK(b != 0) << "0으로 나눌 수 없습니다!";
return a / b;
}
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]);
int result = divide(10, 0); // CHECK(b != 0) 조건 위반
google::ShutdownGoogleLogging();
return 0;
}
✅ CHECK(b != 0)
조건이 만족되지 않으면 FATAL 로그가 출력되고 프로그램이 종료됩니다.
3. 특정 조건에서만 디버깅 로그 출력
DLOG()
를 사용하면 디버그 빌드(NDEBUG
가 정의되지 않은 경우)에서만 로그를 출력할 수 있습니다.
DLOG(INFO) << "디버깅 모드에서만 출력됩니다!";
✅ 릴리즈 빌드에서는 DLOG()
로그가 자동으로 제거되므로 성능 최적화에 유리합니다.
4. 로그 필터링 및 분석
glog는 로그 파일을 자동으로 저장하므로, 이를 활용하여 오류를 분석할 수 있습니다.
grep "ERROR" /var/log/my_project/my_app.*.log
✅ 위 명령어를 실행하면 로그 파일에서 ERROR 메시지만 추출할 수 있습니다.
추가적으로, 특정 시간 범위의 로그를 검색하려면 awk
를 사용할 수도 있습니다.
awk '$2 >= "12:00:00" && $2 <= "14:00:00"' /var/log/my_project/my_app.INFO.log
✅ 12시~14시 사이에 발생한 로그만 필터링하여 분석할 수 있습니다.
5. 원격 로그 전송
서버 환경에서 로그를 원격으로 전송하면 실시간 모니터링이 가능합니다.
glog는 기본적으로 원격 전송 기능을 제공하지 않지만, rsyslog
또는 syslog
와 함께 사용하면 가능합니다.
tail -f /var/log/my_project/my_app.INFO.log | nc logserver.example.com 514
✅ 실시간으로 로그 서버로 전송하여 중앙 집중식 로그 관리를 할 수 있습니다.
디버깅 및 문제 해결 요약
✅ 스택 트레이스를 활용하여 오류 발생 위치 추적 (LOG(FATAL)
)
✅ CHECK() 매크로로 코드 실행 중 조건 검증
✅ DLOG()를 사용하여 디버그 모드에서만 로그 출력
✅ grep/awk를 활용하여 로그 필터링 및 분석
✅ 실시간 원격 로그 전송을 활용한 중앙 집중식 모니터링
다음 장에서는 glog를 활용한 C 프로젝트의 로깅 전략 요약을 설명하겠습니다.
요약
본 기사에서는 C 언어에서 glog를 활용한 대규모 프로젝트 로깅 관리 방법을 다루었습니다.
주요 내용을 정리하면 다음과 같습니다.
✅ glog 개요: Google에서 제공하는 강력한 로깅 라이브러리로, 다양한 로그 레벨과 자동 파일 저장 기능을 지원
✅ 설치 및 설정: 패키지 관리자(apt, yum, brew) 또는 소스 코드로 설치하고, FLAGS_log_dir
로 로그 저장 경로 지정
✅ 기본 사용법: LOG(INFO)
, LOG(WARNING)
, LOG(ERROR)
, LOG(FATAL)
을 활용하여 다양한 로그 기록
✅ 로그 파일 관리: FLAGS_max_log_size
를 설정하여 로그 크기 제한 및 자동 파일 회전 기능 활용
✅ 로그 레벨 최적화: LOG_IF()
, LOG_EVERY_N()
을 사용하여 불필요한 로그 출력 방지
✅ 성능 최적화: 비동기 로깅 구현, FLAGS_stderrthreshold
로 특정 로그 레벨 이상만 출력
✅ 멀티스레드 로깅: glog는 스레드 안전하지만 성능 최적화를 위해 비동기 로깅 기법 적용 가능
✅ 디버깅 및 문제 해결: CHECK()
, DLOG()
, 스택 트레이스 활용, 로그 분석 및 원격 전송 가능
결론
glog를 활용하면 C 프로젝트에서 체계적인 로깅 시스템을 구축할 수 있으며, 성능 저하 없이 효율적인 디버깅과 문제 해결이 가능합니다. 이를 통해 대규모 애플리케이션에서도 안정적인 로깅 환경을 유지할 수 있습니다.