로그를 읽고 쓰기 편리한 라이브러리로 header only파일이라 include만
시켜주면 된다.
소스를 다운받자.
$ git clone https://github.com/gabime/spdlog.git
컴파일시 헤더를 포함시켜준다.
$ g++ main.cpp -I./spdlog/include/ -o main
spdlog
를 이용하여 파일에 로그를 남겨본다.
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
int main(void) {
std::shared_ptr<spdlog::logger> Logger;
Logger = spdlog::basic_logger_mt("HelloLogger", "./hello.log");
Logger->critical("Hello world");
return 0;
}
해당 소스를 컴파일 후 실행하면 hello.log라는 파일이 생성되고
내용을 확인해본다.
[2022-11-12 12:41:35.577] [HelloLogger] [critical] Hello world
로그 파일의 최대 크기
및 최대 백업 개수
를 설정할 수 있는 로테이팅
설정을 해본다.
한 파일에 최대 200byte가 저장될 수 있으며 백업 수는 최대 2개로 설정해본다.
#include "spdlog/spdlog.h"
#include "spdlog/sinks/rotating_file_sink.h"
int main(void) {
std::shared_ptr<spdlog::logger> RotatingLogger;
size_t LogFileMaxSize = 200;
size_t LogFileMaxCount = 2;
RotatingLogger = spdlog::rotating_logger_mt("HelloLogger", "./hello.log", LogFileMaxSize, LogFileMaxCount);
for(int idx = 0; idx < 10; idx ++) RotatingLogger->error("Hello World : {0}", idx);
return 0;
}
소스를 컴파일 후 실행하면 총 3개의 파일이 생성된다.
로그 파일들의 사이즈를 확인해보자.
$ ls -al hello*
-rw-rw-r-- 1 user user 192 Nov 12 12:45 hello.1.log
-rw-rw-r-- 1 user user 192 Nov 12 12:45 hello.2.log
-rw-rw-r-- 1 user user 128 Nov 12 12:45 hello.log
로그 파일들의 내용을 확인해보면 "Hello World : 1"은 사라졌다.
hello.1.log와 hello.2.log는 3개의 로그가 들어가있다.
$ grep -r "Hello" ./hello*
./hello.1.log:[2022-11-12 12:45:26.995] [HelloLogger] [error] Hello World : 5
./hello.1.log:[2022-11-12 12:45:26.995] [HelloLogger] [error] Hello World : 6
./hello.1.log:[2022-11-12 12:45:26.995] [HelloLogger] [error] Hello World : 7
./hello.2.log:[2022-11-12 12:45:26.995] [HelloLogger] [error] Hello World : 2
./hello.2.log:[2022-11-12 12:45:26.995] [HelloLogger] [error] Hello World : 3
./hello.2.log:[2022-11-12 12:45:26.995] [HelloLogger] [error] Hello World : 4
./hello.log:[2022-11-12 12:45:26.995] [HelloLogger] [error] Hello World : 8
./hello.log:[2022-11-12 12:45:26.995] [HelloLogger] [error] Hello World : 9
별도의 파일로 로그를 관리하는 것이 아닌 syslog
에 같이 로깅을 해본다.
#include "spdlog/spdlog.h"
#include "spdlog/sinks/syslog_sink.h"
int main(void) {
std::shared_ptr<spdlog::logger> SysLogger;
SysLogger = spdlog::syslog_logger_mt("syslog", "HelloLogger", LOG_PID);
SysLogger->error("Hello World");
return 0;
}
syslog를 확인해본다.
$ tail -n 100 /var/log/syslog | grep HelloLogger
Nov 12 12:56:23 dev HelloLogger[3216]: Hello World
최소 로그 레벨
을 설정하고 해당 레벨 이상만 로깅해본다.
아래의 예에서는 info로 레벨을 설정하였으니, debug레벨의 로그는 기록되지 않는다.
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
int main(void) {
std::shared_ptr<spdlog::logger> logger;
logger = spdlog::basic_logger_mt("logger", "./hello.log");
logger->set_level(spdlog::level::info);
spdlog::flush_on(spdlog::level::info);
logger->debug("hello world");
logger->info("hello world");
logger->warn("hello world");
logger->error("hello world");
logger->critical("hello world");
return 0;
}
로그파일을 확인해보면 debug레벨은 기록이 안되어 있다.
[2022-11-12 13:01:04.561] [logger] [info] hello world
[2022-11-12 13:01:04.561] [logger] [warning] hello world
[2022-11-12 13:01:04.561] [logger] [error] hello world
[2022-11-12 13:01:04.561] [logger] [critical] hello world
로그 레벨은 다음과 같이 trace부터 critical순으로 높은 값을 가진다.
trace -> debug -> info -> warn -> error -> critical
다양한 포맷팅
을 활용하여 메세지를 생성해본다.
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
int main(void) {
std::shared_ptr<spdlog::logger> logger;
logger = spdlog::basic_logger_mt("logger", "./hello.log");
logger->set_level(spdlog::level::debug);
spdlog::flush_on(spdlog::level::info);
logger->debug("hello world");
logger->info("{1} {0}", "hello", "world");
logger->warn("float {:03.2f}", 3.989);
logger->error("{:>7}", "hello world");
logger->error("{:>7}", "hello");
logger->critical("{:08d}", 10);
logger->critical("{:03d}", 1011);
return 0;
}
로그 파일의 내용을 확인해본다.
[2022-11-12 13:04:03.949] [logger] [debug] hello world
[2022-11-12 13:04:03.949] [logger] [info] world hello
[2022-11-12 13:04:03.950] [logger] [warning] float 3.99
[2022-11-12 13:04:03.950] [logger] [error] hello world
[2022-11-12 13:04:03.950] [logger] [error] hello
[2022-11-12 13:04:03.950] [logger] [critical] 00000010
[2022-11-12 13:04:03.950] [logger] [critical] 1011
시간에 대한 포맷팅을 적용해본다.
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
int main(void) {
std::shared_ptr<spdlog::logger> logger;
logger = spdlog::basic_logger_mt("logger", "./hello.log");
logger->set_level(spdlog::level::debug);
spdlog::flush_on(spdlog::level::info);
spdlog::set_pattern("[%Y-%m-%d %X.%e][%n][%l] %v");
logger->error("hello");
spdlog::set_pattern("[%Y-%B-%d (%A) %r %z][%n][%l] %v");
logger->error("world");
return 0;
}
로그 파일의 내용을 확인해본다.
[2022-11-12 13:06:22.754][logger][error] hello
[2022-November-12 (Saturday) 01:06:22 PM +00:00][logger][error] world
포맷 별 결과는 다음과 같다.
format | result |
---|---|
%a,%A | Fri,Friday |
%b,%B | Oct,October |
%c,%C | Fri Oct 22 14:35:59 2021,21 |
%d,%D | 22,10/22/21 |
%e,%E | 963,1634880959 |
%f,%F | 963224,963224959 |
%h,%H | Oct,14 |
%i,%I | 17,02 |
%l,%L | error,E |
%m,%M | 10,35 |
%n | FormattingLoggerName |
%o,%O | 0,0 |
%p,%P | PM,63959 |
%r,%R | 02:35:59 PM,14:35 |
%S | 59 |
%t,%T | 63959,14:35:59 |
%u | 17106 |
%v | world |
%x,%X | 10/22/21,14:35:59 |
%Y | 2021 |
%z | +09:00 |
byte형 데이터를 hex
로 표현
해본다.
#include "spdlog/spdlog.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/fmt/bin_to_hex.h"
int main(void) {
std::shared_ptr<spdlog::logger> logger;
logger = spdlog::basic_logger_mt("logger", "./hello.log");
unsigned char data[3] = {0xa5, 0xde, 0x66};
logger->error("bin to hex : {:xsn}", spdlog::to_hex(std::begin(data), std::begin(data) + sizeof(data)));
return 0;
}
로그파일의 내용을 확인해보자.
[2022-11-12 13:08:18.218] [logger] [error] bin to hex : a5de66
포맷 별 결과는 다음과 같다.
예시에서 쓴 xsn은 소문자형태(x)와 구분자를 없애며(s) 위치(0000)와 개행(\n)을 제거(n)한 조합이다.
format | result |
---|---|
%x | "\n0000: a5 de 66" |
%s | "\n0000: a5de66" |
%p | "\na5 de 66" |
%n | " a5 de 66" |
%a | "0000: a5 de 66 ..f" |
%X | "0000: A5 DE 66" |