Serach

레이블이 etc.인 게시물을 표시합니다. 모든 게시물 표시
레이블이 etc.인 게시물을 표시합니다. 모든 게시물 표시

2013년 10월 11일 금요일

게임이 재미있는 4가지 이유

여러분, 혹시 호이징거의 이론을 아시나요?

네덜란드의 고전학자인 호이징거는 2차 세계대전 당시 독일군에 의해서 가택연금된 상태에서
세기의 명저를 남겼는데 그 중 게임 제작자들이 알고 있어야 하는「호모 루덴스」입니다.

「호모 루덴스」는 놀이를 하는 인간에 대한 놀라운 통찰력을 담고 있습니다.
인간은 본질적으로 유희(遊戱)를 추구하고, 인간 문명의 원동력은 바로 '놀이' 라는 것이 이것의 핵심 입니다.

뜬금없이 제가 이 「호모 루덴스」라는 것을 소개 했는지 이제 시작합니다.


호이징거의 이론은 프랑스의 학자인 <로제 카이와>에 의해서 확대 발전 되었다고 합니다.
로제 카이와는 호이징거의 비판론 으로 시작되었지만, 그의 생각을 발전시켜서 놀이에 대한 학문적 가치를 더욱 높였습니다.

호이징거가 인간의 본질을 연구하면서 '놀이'를 조명했고,
로제 카이와는 '놀이' 자체만을 연구 하여 20세기 최고의 놀이학자가 되었지요.

로제 카이와는 그의 저서인 「놀이와 인간」을 통해서
역할 놀이인 '미미크리(Mimicry)', 경쟁 놀이인 '아곤(Agon)', 확률 놀이인 '알레아(Alea)', 몰입 놀이인 '일링크스(Ilinx)'
위 4가지로 놀이를 분류 했습니다.


미미크리(Mimicry)

역할 놀이인 미미크리는 특정한 누군가를 흉내내거나 모방하는 놀이를 의미 합니다.

어린시절 소꿉놀이, 배역이 정해져 있는 연극과 영화 이들은  미미크리의 범주에 속해 있으며,

또한 애니메이션 혹은 게임의 주인공과 똑같은 옷을 입거나, 같은 행동을 하는 '코스튬 플레이' 역시 미미크리 놀이에 속한다.

이 놀이를 게임으로 보자.

게임상에서의 플레이어는 가장 먼저 무엇을 하는가?

플레이어는 가장 먼저 종족 혹은 캐릭터를 선택합니다.

사람들은 게임 안에서 캐릭터, 즉 역할을 가지고 시작합니다.

탱커가 되어 몬스터들로 부터의 공격을 막아주며 아군을 지켜주거나, 도시의 시장이 되어 도시를 건설하기도 하며,

사령관이 되어 전투를 지휘 하기도 한다.



아곤(Agon)

경쟁 놀이인 아곤은 일정한 규칙 안에서 참가자 모두가 경쟁관계를 형성하며 투쟁하는 놀이를 말한다.

참가자들에게 공정한 규칙이 주어지며, 명확한 승패가 결정되는 놀이가 된다.

인간은 똑같은 규칙과 삶 속에서 최고가 되고자 하는 욕구가 있기 때문에 서로 경쟁하게 됨으로 자연스레 아곤 놀이가 발동된다.

반면,

게임은 이 일정한 규칙과 속에서 서로 경쟁을 하는 재미를 주고있다.

게임 제작자들이 게임을 제작하면서 미미크리 다음으로 생각해야 하는것이 바로 경쟁 놀이인 아곤 이다.


알레아(Alea)

우연 놀이인 알레아는 라틴어로 '주사위 놀이' 라는 의미이다.

주사위는 정육면체 모양의 도구로 각 면 마다 1~6까지의 숫자가 있으며 중복은 없다.

주사위를 던졌을 때 어떠할까?

자신의 의지대로 숫자가 나오는 것이 아닌 확률, 즉 '운' 에 맡기는 놀이 이다.

일상생활의 알레아 놀이는 어디에 있을까? '운' 이라는 단어에서 가장 떠오르는 복권 이 역시도 알레아 놀이 이며,

화투, 마작, 포커, 슬롯머신 역시 알레아 놀이에 속한다.

주사위는 단순히 운으로 결정되는 놀이정도로 알고 있다.

하지만 정확히는 확률이며 통계이다.

컴퓨터 게임 전체에 확률과 통계가 있는데 이를 '밸런싱' 이라는 이름으로 곳곳에 있다.

이 '밸런싱' 은 플레이어와 NPC 그리고 오브젝트의 행동에 의해 결정 된다.

따라서 게임 제작자들은 유저가 재미를 느끼도록 밸런싱 조절에 신경을 써야 할 것이다.


일링크스(Ilinx)

몰입 놀이인 일링크스는 고도의 집중력이 필요한 놀이를 의미 한다.

서커스, 롤러코스터, 스키 처럼 일시적으로 무아지경의 상태를 일으키는 놀이 이지만

현기증이라기보다 난관 상태에서 경험하는 일종의 몰입 상태 라고 볼 수 있다.

컴퓨터 게임은 플레이어에게 끊임없이 도전 과제를 준다.

플레이어는 이 과제를 수행하기 위해서 한계에 도전하고, 극복해 가며, 그 자체에 몰입을 하게 된다.

일링크스 놀이는 앞에서 말했던 다른 분류의 놀이들 속에 녹아 들어 있다.

미미크리, 아곤, 알레아 이 세 가지의 놀이가 컴퓨터 게임 자체를 이루는 구성 요소 라면

일링크스는 게임을 즐기는 사람의 감정 상태를 말 한다.

즉. 세 가지의 놀이가 플레이어를 일링크스의 상태로 이끌어 가는 셈 이다.



여기 까지 로제 카이와의 「놀이와 인간」에서 분류한 네 가지의 놀이를 살펴 보았다.

게임이 살아남기 위해서는 위 네 가지의 놀이가 성립해야 하며 지속적인 순환이 되어야 한다.

아마도 위의 네 가지 단어를 처음 들어 보아서 혼란스러울 수도 있다.

하지만 게임 제작자 에게 있어서 중요하지만 간단한 내용 이므로 꼭 알아두자.


정리

ⓐ  인류학자인 호이징거는 인간은 놀이하는 동물이라고 말했다.
이와 같이 놀이는 인간 문명 창조의 원동력으로, 매우 위대한 행위이다.

ⓑ 놀이학자인 로제 카이와는 인간이 재미를 느끼는 놀이를
'미미크리', '아곤', '알레아', '일링크스' 라는 네 가지 유형으로 나누었다.

ⓒ 미미크리는 게임 속에서 플레이어가 맡는 혁할이다.

ⓓ 아곤은 게임의 진행을 총괄하는 규칙의 모음이다.

ⓔ 알레아는 플레이어가 게임을 진행하며 느끼는 공정함, 밸런싱을 의미한다.

ⓕ 일링크스는 플레이어가 게임에서 승리자가 되기 위해서 극복해야 할
도전 과제에 온 정신을 몰입하면서 느끼는 감정 상태를 의미한다.

ⓖ 게임이 재미있는 이유는 놀이의 네 가지 유형인
미미크리, 아곤, 알레아, 일링크스가 상호 복합적으로 게임에 녹아있기 때문이다.




TCP와 UDP의 차이점

1. Connection Oriented Protocol vs. Connectionless Protocol

TCP는 3-way handshaking을 통하여 Session을 수립 후에 통신을 하는 Connection Oriented (연결지향형) Protocol 입니다. 그에 반해 UDP는 상대방이 받던 받지 못하던 무작정 데이터를 전송하는 Connectionless (비연결형) Protocol 입니다. 그럼, 언제 UDP를 사용할까요? 

예를 들어 DNS 같은 경우 예로 보세요. 누군가 DNS 서비스를 요청할 때마다 TCP처럼 Session을 맺고 통신을 한다면 속도도 느리고, 서버 리소스도 엄청나게 소모될 겁니다. 그런가 하면 NMS(Network Management Server)가 5분에 한번씩 장비 상태를 점검하기 위해 정보를 읽어오는데 수백, 수천대의 장비와 Session을 맺어야 한다면 이것도 마찬가지로 문제가 있겠죠? 그래서, SNMP(Simple Network Management Protocol)는 UDP를 사용하는 Protocol입니다.

2. Reliable vs. Best Effort

TCP는 데이터 전송에 문제가 발생했을 경우, 재전송 요청 등을 통해서 데이터가 정확하게 전송되는 것을 보장하는 Protocol인 반면, UDP는 에러가 생기든 말든... 보내는 놈이나 받는 놈이나 신경을 쓰지 않는 Protocol입니다. 이런, 이따위 Protocol을 어디에 쓸까요?

재전송을 하면 안되는 서비스들이 있습니다. 대표적인 예가 바로 Real-Time Protocol입니다. 전화를 하고 있다고 가정해 보세요. '여''보''세''요'라는 4개의 데이터를 전송했는데, '세'를 못 받았다고 다시 보내달라고 하면 '여보요세'가 될겁니다. 그냥 '여보X요'로 전달하는게 더 낫겠죠?

그런가 하면 Multicast 서비스가 UDP를 사용합니다. 1:N으로 통신하는 방식에서 한놈이 데이터를 받지 못했다고 재전송 요청을 한다고 생각해보세요. 제대로 받은 놈들도 해당 데이터를 다시 받아서 처리해야 한다는 문제가 발생할 수 있습니다. 그래서 UDP를 사용하는거죠!

그리고, UDP는 상대방이 잘 받았는지 못 받았는지 신경을 쓰지 않으니 Ack가 별도로 필요없겠죠? ^^

3. Sequence Number vs. Non-Sequencing

TCP는 데이터 유실 등을 확인하기 위하여 데이터마다 Sequence Number라는 번호를 붙여서 전송을 합니다. 하지만, UDP는 데이터 유실에 관심이 없기 때문에 Sequence Number가 없는 Non-Sequencing Protocol 입니다. 그럼, 데이터를 전송할 때 상이한 경로로 전송되서 나중에 보낸 데이터가 먼저 도착하게 되면 어떻게 되나요? 예를 들어 '여''보''세''요'를 전송했는데 '여''세''보''요' 순으로 도착을 한겁니다.

이렇게 데이터 전송 순서를 알아야 하는 서비스는 RTP(Real-time Protocol)과 같은 Sequence Number 기능을 가지고 있는 기술과 함께 쓰이거나 어플리케이션 수준에서 Sequencing을 수행합니다.
 
4. Half-duplex vs. Full-duplex

Layer 2에서의 duplex가 아니구요, 한개의 Port를 이용하여 [upload/download]가 가능한가에 대한 부분입니다. 원칙적으로 UDP는 Half-duplex이고 TCP는 Full-duplex 입니다. 하지만, UDP도 어플리케이션 개발 방식에 따라 Full-duplex 방식으로도 설계가 가능합니다. 그래서,TCP를 Full-dulpex 방식이라고 이야기하지만, UDP를 Half-duplex 또느 Full-duplex 방식이라고 정의하지는 않습니다.

5. Control vs. Don't care

TCP는 Error-Contol, Flow-Control 등 이것저것 제어를 많이 합니다.
하지만, UDP는 그런건 그냥 짜증스럽고 귀잖을 뿐입니다. 

2013년 10월 10일 목요일

Sublime Text2 설정 & 팁

설치 패키지 목록 
git
git sidebar
BracketHigHlighter - 괄호 하이라이터
SublimeCondelntel - 코드 추적
Python Auto-Complete - 코드 자동 완성
SideBarEnhancements - 사이드바 확장
inputHelper - 한글 입력
SFTP
SublimeREPL - 가상환경 설정


코딩 컨벤션 & 스타일
Python Flake 8 Lint
Python PEP8 AutoFormat






자주 쓰게되는 단축키

  • 행 들여쓰기 · 내어쓰기
    win: ctrl+[ · ctrl+], mac: cmd+[ · cmd+]
    기본적으로 탭키를 사용할 수도 있지만, 한참 코드를 작성하다가 행단위 들여쓰기를 제어하려면 이 방식이 편하기도.
  • 행 상하 이동
    win: ctrl+shift+↕, mac: cmd+ctrl+↕
  • 코드블럭 접기 · 펴기
    win: ctrl+shift+[ · ctrl+shift+], mac: cmd+opt+[ · opt+shift+]
  • 찾아바꾸기
    win: ctrl+h, mac: cmd+opt+f
  • 여러파일에서 찾기
    win: ctrl+shift+f, mac: cmd+shift+f
  • GoTo Anything
    win: ctrl+p, mac: cmd+p
    GoTo Anything을 호출한다. 해당기능은 아래서 살펴볼 것이다.
  • Command Palette
    win: ctrl+shift+p, mac: cmd+shift+p
    Command Palette를 호출한다. 해당기능은 아래서 살펴볼 것이다.



    유용한 패키지 목록

    내가 쓰고 있는 패키지는 다음과 같다. 코딩을 즐겁게 해준다 ;)
    • BracketHighlighter
      블럭영역의 시작과 끝을 눈에 좀 더 잘 띄게(?) 해준다. 기본은 옅은 밑줄만 쳐져 있어 분간이 어려웠다.
    • Theme - Soda
      조금은 뚱뚱한 느낌이 드는 기본 테마를 변경해준다. Theme는 에디터 내부 문법강조 컬러를 변경해주는 Color Scheme과는 다른 개념으로, 프로그램 전체의 룩앤필을 칭한다.
    • RailsCasts Theme
      위의 Theme와는 다르게 이건 Color Scheme을 변경해준다. RailsCast 스타일이다. 현재까지 써본것중엔 기본으로 포함된 Twilight과 함께 제일 편안한 색상이다.
    • Package Control
      위에서 살펴보았다. 다양한 패키지를 커맨드 팔렛트에서 관리할 수 있도록 해준다.
    • Quick File Creator
      커맨드 팔렛트에서 파일, 폴더 등을 생성할 수 있다. 마우스 안녕~
    • Emmet (ZenCoding)
      젠코딩을 가능하게 해준다. html 코딩할 때 이거 없으면 피곤하다.
      [2012.01.26] ZenCoding이 Emmet으로 진화했다. Fuzzy Search 기능 최고!
    • SCSS
      SCSS를 위한 문법강조를 지원한다.
    • ERB Insert and Toggle Commands
      ERB 블럭 입력을 도와준다.
    • SublimeCodeIntel
      코드인텔리전스 기능이다. 지원언어는 다음과 같다.
      PHP, Python, RHTML, JavaScript, Smarty, Mason, Node.js, XBL, Tcl, HTML, HTML5, TemplateToolkit, XUL, Django, Perl, Ruby, Python3
    • SFTP
      FTP, FTPS, SFTP 지원을 위한 녀석.
      _유료. 이것도 라이센스키를 입력하지 않으면 구매권유 팝업이 뜬다.
    • Automatic Backups
      파일을 저장할때마다 백업본을 생성해준다.







    우분투 런처 등록

    1. 우선 Sublime Text 2 를 다운로드 받습니다. (http://www.sublimetext.com/2)
    2. 아무데나 압축을 풀어줍니다.
    $ tar jxvf Sublime Text 2.0.1 x64.tar.bz2
    3. /opt 폴더로 압축 푼 폴더를 옮깁니다.
    sudo mv Sublime Text 2/ /opt/
    4. /usr/bin 폴더에 실행파일을 심볼릭 링크 걸어줍니다.
    $ sudo ln -s /opt/Sublime Text 2/sublime_text /usr/bin/sublime
    5. application 에 등록 해주는 단계입니다. desktop 파일을 만들어 줍니다.
    $ sudo sublime /usr/share/applications/sublime.desktop
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    [Desktop Entry]
    Version=1.0
    Name=Sublime Text 2
    # Only KDE 4 seems to use GenericName, so we reuse the KDE strings.
    # From Ubuntu's language-pack-kde-XX-base packages, version 9.04-20090413.
    GenericName=Text Editor
     
    Exec=sublime
    Terminal=false
    Icon=/opt/Sublime Text 2/Icon/48x48/sublime_text.png
    Type=Application
    Categories=TextEditor;IDE;Development
    X-Ayatana-Desktop-Shortcuts=NewWindow
     
    [NewWindow Shortcut Group]
    Name=New Window
    Exec=sublime -n
    
    * Unity 를 사용한다는 가정 입니다. +_+ 현재 상황에 맞게 고쳐 쓰세요. (다른 파일 참고 하심 됩니다.)
    6. 기본 프로그램을 Sublime Text 로 설정하는 방법입니다. 다른 에디터를 기본프로그램으로 쓰고 계시다면 안하셔도 됩니다.
    $ sudo sublime /usr/share/applications/default.desktop
    위 파일을 열어 기존의 기본 에디터(gedit)를 sublime 으로 변경해줍니다.
    (ex, gedit.desktop 을 모두 sublime.desktop 으로 변경)

glog 사용법

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";
}
Google glog는 많은 공용 로깅 테스크들을 간소화시킨 일련의 매크로들을 정의한다. severiy level 에 의해서 메시지들을 남길 수 있으며, 커맨드 라인을 통해서 로깅 작용을 컨트롤 할 수 있고 상태에 따른 로그를 남길 수 있고 기대했던 상태가 나오지 않을 경우에는 프로그램을 종료시킬 수도 있으며 자신만의 로깅 레벨을 도입할 수도 있다. 이 문서는 glog에서 지원하는 기능들에 대해서 기술한다. 이 문서는 라이브러리의 모든 사항들에 대해서 기술되어 있지 않지만, 매우 유용할 것이다. 약간 일반적이지 않은 사항들을 찾고 싶다면 src/glog 디렉토리에 있는 헤더 파일들을 체크 해 보길 바란다.

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
Google gflags 라이브러리가 설치되어 있지 않다면, "GLOG_" 라는 접두어를 사용한 플래그를 환경 변수를 통해서 설정을 해주어야 한다. 예를 들면,
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="")

값이 명시되면, 로그파일들은 기본 디렉토리 대신에 이 디렉토리에 남겨진다.
제공되는 API는 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";
"Got lots of cookies" 메시지는 num_cookies 변수가 10을 넘을 때만 남겨진다. 코드가 여러 번 실행된다면, 이 매크로는 특정 순간에만 메시지를 남기는데 유용할 것이다. 이런 종류는 로그는 정보 메시지들에 매우 유용하다..
LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookies";
위 라인은 첫 번째, 11번째, 21번째 ... 실행 시에만 메시지를 출력한다. google::COUNTER 값은 몇 번 반복이 일어났는지를 확인할 때 사용된다.
다음과 같이 상태에 따라서 그리고 임의로 남기도록 조합형태로 사용할 수 있다.
LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER << "th big cookies";
매번 메시지를 남기는 것 대신에 처음 n 이 나타날 때로 출력을 제한할 수도 있다:
LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
처음 20 번 실행되는 동안에 로그 메시지들을 출력한다.

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!";
equality/inequality 체크를 하는 다양한 헬퍼 매크로들이 있다 -  CHECK_EQ, CHECK_NE, CHECK_LE, CHECK_LT, CHECK_GE, CHECK_GT. 이 매크로들은 두 값들을 비교하고 기대했던 결과가 나오지 않을 때는 두 값을 포함한 FATAL 메시지를 남긴다. 값들은 정의된 operator<<(ostream, ...) 을 가진다.
다음과 같이 에러 메시지를 붙일 수 있다:
CHECK_NE(1, 2) << ": The world must be ending!";
우리는 각각의 인자는 정확히 한번만 계산이 되고, 함수 인자로서 전달이 될 수 있는 것들은 어떤 것이든 전달이 될 수 있도록 주의를 하고 있다. 특히, 인자들이 구문의 끝에서 파괴되어서 끝나는 임시 표현일 수도 있을 것이다. 예를 들면:
CHECK_EQ(string("abc")[1], 'b');
컴파일러는 인자들 중에 하나가 포인터이고 다른 하나가 NULL 이라면 에러를 남길 것이다. 이에 대한 차선책으로, 간단히 원하는 포인터의 타입에 NULL 로 static_cast 를 하는 것이다.
CHECK_EQ(some_ptr, static_cast<SomeType*>(NULL));
아직 좋지 안다, CHECK_NOTNULL 매크로를 사용하면:
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";
VLOG 를 사용하면, 낮은 단계의 verbose 레벨의 메시지들이 좀더 남겨질 수 있다. 예를 들면, if --v==1, VLOG(1) 는 로그를 남길 것이고 VLOG(2)는 로그를 남기지 못할 것이다. 이는 INFO가 0이고 ERROR이 2인 severity 레벨과는 반대이다. 1의 --minloglevel은 WARNING 과 그 이상의 메시지를 남길 것이다. VLOG 매크로와 --v 플래그에 대해서 어떤 정수라도 명시할 수 있으며, 그 값들에 대한 일반적인 값은 양의 정수들이다. 예를 들면, VLOG(0)을 사용했다면, 로그를 남기지 않으려면 --v=-1을 명시하거나 0보다 낮은 값을 사용해야 한다. 이는 대부분의 상황에서 기본적으로 장황한 로그를 남기고 싶어하지 않기 때문에 유용한 이슈이다. VLOG 매크로는 항상 INFO 로그 레벨에서 로그를 남긴다(모든 것에서 로그를 남길 때)
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)을 출력한다.
(c) 에서 보인 와일드 카드 기능은 '*' (0이나 문자들과 매치되는)와 '?'(단일 문자와 매치되는) 와일드 카드 둘 다 지원한다. command line flags 도 확인해 보기 바란다.
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) << .... ;
}
Verbose 레벨 컨디션 매크로 VLOG_IF, VLOG_EVERY_N, VLOG_IF_EVERY_N 은 LOG_IF, LOG_EVERY_N, LOG_IF_EVERY 와 유사하게 행동하지만, 로깅 단계에 대한 레벨 넘버는 severity 레벨과 반대로 적용된다.
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() 에 의해서 설치된다. 다음은 시그널 핸들러로부터의 출력 예제이다.
*** 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)
기본적으로, 시그널 핸들러는 standard error로 failure dump를 작성한다. InstallFailureWriter() 를 이용해서 도착지를 커스터마이징할 수 있다.

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);
}
기본적으로, glog는 스택 트레이스를 덤프하고 프로그램을 1 상태 코드로 끝나게 만들려고 시도한다. 스택 트레이스는 glog 가 스택 트레이싱을 지원하는 아키텍쳐에서 실행했을 때만 만들어진다.

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>
컴파일러는 명시한 정수형 값보다 작은 단계의 로그 메시지를 제거할 것이다. VLOG 는 severity 레벨 INFO(숫자로 0)에서 로그를 남기기 때문에, GOOGLE_STRIP_LOG를 1로 설정하거나 그 이상으로 설정을 한다면 INFO 로그 메시지들과 함께 VLOG로 지정된 모든 로그 메시지들은 제거될 것이다.

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";
하지만, glog/logging.h 에 정의되어 있는 INFO, WARNING, ERROR, FATAL  을 더이상 사용할 수 없다.
#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);
windows.h 에 정의되어 있는 ERROR 가 필요하지 않다면, 종종 작동하지 않는 몇 가지 대안이 있다.
  • #include <windows.h> 전에 #define WIN32_LEAN_AND_MEAN 이나 NOGDI
  • #include <windows.h> 다음에 #undef ERROR
좀더 자세한 내용은 여기로.