C++ std::cout으로 콘솔 꾸미기
뇌리에 스치는 불편함
본좌가 로봇 제어 프로그램을 개발할 때 뇌리에 스쳐 지나간 것이 있다. 메세지를 출력할 때 DEBUG, INFO, WARN, ERROR, CRITIAL 등을 출력하는데 모두 출력을 기본으로 했을때 너무 읽기 불편했다... 그래서 출력 시 색상, 필체, 배경 등을 내 맘대로 끄적끄적 바꾸면 마음이 편안해질 것만 같았다. 하던 작업을 모두 멈추고 구글링에 인터럽트가 걸렸다. 만약 각 로그 레벨을 다른 색상으로 찍어내고 싶을때는 어떻게 해야 할까?색상, 포멧 변경
코드는 다음과 같다."\033[{FORMAT_ATTRIBUTE};{FORGROUND_COLOR};{BACKGROUND_COLOR}m{TEXT}\033[{RESET_FORMATE_ATTRIBUTE}m"
중괄호에 들어갈 변수들은 ANSI_escape_code
를 참고하면 된다. 위 링크에 요롷게 색상 표? 가 있다.

"ESC[30;47m{TEXT}"
ESC
코드는 \033
이다.
예를들어 다음과 같은 출력이 있다고 해보자.
[DEBUG], From: [int main(int, char **)], Message Debug message
[INFO], From: [int main(int, char **)], Message Info message
[WARN], From: [int main(int, char **)], Message Warn message
[ERROR], From: [int main(int, char **)], Message Error message
[CRITICAL], From: [int main(int, char **)], Message Critical message
여기에 색상을 알흠답게 입혀주면 아주 예쁘게 만들 수 있다.
[INFO], From: [int main(int, char **)], Message Info message
[WARN], From: [int main(int, char **)], Message Warn message
[ERROR], From: [int main(int, char **)], Message Error message
[CRITICAL], From: [int main(int, char **)], Message Critical message
[DEBUG], From: [int main(int, char **)], Message Debug message
[INFO], From: [int main(int, char **)], Message Info message
[WARN], From: [int main(int, char **)], Message Warn message
[ERROR], From: [int main(int, char **)], Message Error message
[CRITICAL], From: [int main(int, char **)], Message Critical message
[INFO], From: [int main(int, char **)], Message Info message
[WARN], From: [int main(int, char **)], Message Warn message
[ERROR], From: [int main(int, char **)], Message Error message
[CRITICAL], From: [int main(int, char **)], Message Critical message
간단하게 예를 만들어 보았다.
/* Printer.h */
#ifndef __PRINTER__
#define __PRINTER__
#include <iostream>
#include <sstream>
/* FOREGROUND */
#define RST "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
#define KYEL "\x1B[33m"
#define KBLU "\x1B[34m"
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"
#define FRED(x) KRED x RST
#define FGRN(x) KGRN x RST
#define FYEL(x) KYEL x RST
#define FBLU(x) KBLU x RST
#define FMAG(x) KMAG x RST
#define FCYN(x) KCYN x RST
#define FWHT(x) KWHT x RST
#define BOLD(x) "\x1B[1m" x RST
#define UNDL(x) "\x1B[4m" x RST
namespace utilties
{
enum LogLevel
{
DEBUG = 0,
INFO = 1,
WARN = 2,
ERROR = 3,
CRITIAL = 4,
};
class Printer
{
public:
Printer(LogLevel level) : _level(level)
{
switch (level)
{
case DEBUG:
_prefix << "[" << FGRN("DEBUG") << "]";
break;
case INFO:
_prefix << "[" << FMAG("INFO") << "]";
break;
case WARN:
_prefix << "[" << FYEL("WARN") << "]";
break;
case ERROR:
_prefix << "[" << FRED("ERROR") << "]";
break;
case CRITIAL:
_prefix << "[" << FCYN("CRITICAL") << "]";
break;
}
}
private:
LogLevel _level;
std::stringstream _prefix;
public:
void log(std::string whrere, std::stringstream stream)
{
std::cout << _prefix.str() << ", From: [" << whrere << "]"
<< ", Message " << stream.str() << std::endl;
}
};
} // namespace utilties
/* main.cpp */
#include <iostream>
#include <Printer.h>
#include <sstream>
using namespace utilties;
int main(int argc, char *argv[])
{
Printer(LogLevel::DEBUG).log(__PRETTY_FUNCTION__, std::stringstream() << "Debug message");
Printer(LogLevel::INFO).log(__PRETTY_FUNCTION__, std::stringstream() << "Info message");
Printer(LogLevel::WARN).log(__PRETTY_FUNCTION__, std::stringstream() << "Warn message");
Printer(LogLevel::ERROR).log(__PRETTY_FUNCTION__, std::stringstream() << "Error message");
Printer(LogLevel::CRITIAL).log(__PRETTY_FUNCTION__, std::stringstream() << "Critical message");
return 0;
}
글자 형태 변경
italic이나 bold로 표현하고 싶을 때는"\033[{FORMAT_ATTRIBUTE};{FORGROUND_COLOR};{BACKGROUND_COLOR}m{TEXT}\033[{RESET_FORMATE_ATTRIBUTE}m"
{FORMAT_ATTRIBUTE}
부분을 채워 넣으면 된다.
만약 흰색 배경 + 검정 글자 + bold로 설정하려면
"ESC[1;30;47m{TEXT}"
출력 형태 변경
출력 형태는 std::oct, std::dec, std::hex등으로 변경한다. 출력 연산자(>>)와 입력 연산자(<<)와 함께 사용될 수 있다.#include <iostream>
#include <sstream>
int main(int argc, char *argv[])
{
std::cout << std::hex << 10 << std::endl;
std::cout << std::dec << 0x0C << std::endl;
std::cout << std::oct << 9 << std::endl;
/* 스트림 진법 형식이 바뀌어지면 계속 유지된다. */
std::cout << std::hex << 10 << ", " << std::dec << 13 << std::endl;
int in;
/* 2A를 hex 로 읽어들이자 */
std::istringstream("2A") >> std::hex >> in;
std::cout << std::dec << in << ", " << std::hex << in << ", " << std::oct << in << std::endl;
return 0;
}
NOTE_조작자에 의해 한 번 스트림의 진법 형식이 바뀌면 계속 유지된다. 즉 한변 변경하면 다시 변경해야 한다.
ex) std::cout >> std::hex >> 13 >> std::dec >> 13 >> std::endl;
공백 자릿수 표현
std::setw과 std::setfill를 쓰거나 boost라이브러리를 사용한다. boost 라이브러리를 사용하려고 간단하게 CMakeLists.txt에 추가해야할 라인이 있다. 패키지를 찾고 타겟에 링크를 걸어주면 된다.find_package(Boost COMPONENTS system filesystem REQUIRED)
add_executable(${PROJECT_NAME}_ex3 ex3.cpp)
target_link_libraries(${PROJECT_NAME}_ex3 PUBLIC ${Boost_LIBRARIES})
#include <boost/format.hpp>
#include <iomanip>
#include <ios>
#include <iostream>
int main(int argc, char *argv[])
{
/* Using setw, setfill */
std::cout << "0x" << std::setw(2) << std::setfill('0') << std::hex << 10 << std::endl;
std::cout << std::showbase << std::setw(2) << std::hex << 10 << std::endl;
/* Using boost */
std::cout << boost::format("0x%02x\n") % 10;
return 0;
}
참고
- stackoverflow
- 공백 채우기
- example
- ANSI escape code
- colorize git
- 전문가를 위한 C++