티스토리 뷰
목차
[디자인패턴] Qt 싱글톤 패턴, 로그 생성 프로그램
Qt에서 디자인패턴 중 싱글톤 패턴 기반으로 로그 파일을 생성하는 프로그램입니다. Qt도 C++을 기초로 제작된 언어라 싱글톤 패턴 소스는 C++의 것을 그대로 사용했습니다. 특별한 경우가 아닌 이상, C++ 디자인패턴 소스는 Qt에서도 구동됩니다.
이 포스트의 전체 프로젝트 파일은 아래 링크를 누르시면 받을 수 있습니다.
우선, 실행 화면부터 보시죠. 메인 화면에는 메시지 레벨 3단계가 표시됩니다. UI는 꽤 단순하죠? 로그를 생성할 때, 메시지 레벨이 존재합니다. 위의 버튼에 보이는 ERROR, WARNING, INFORMATION으로 총 3개입니다.
디자인패턴 프로그램 코드상에서 레벨을 지정해 Qt Creator의 디버그 창에서만 메시지를 찍을 것인지, 해당 내용을 로그 파일에 남길 것인지 결정할 수 있습니다.
그리고 레벨 3단계는 로그 파일에도 그대로 찍히게 됩니다.
[Singleton design pattern Qt]
위의 그림 중 왼쪽은 Qt Creator의 디버그 창(Application Output, 편하게 디버그 창으로 부름)입니다.
우측은 실제 프로그램이고요. 버튼을 누를 때마다 좌측처럼 메시지가 출력됩니다. 저 출력되는 메시지가 파일에도 쓰이죠. 물론, 위에서 설명했다시피, 설정에 따라 파일에 쓰이는 메시지는 매번 다를 수 있습니다.
[Singleton design pattern Qt]
디자인패턴 중 싱글톤 패턴으로 생성한 파일입니다. 파일 내용을 알려드리겠습니다.
15 - 시時
23 - 분分
36 - 초秒
135 - 밀리 세컨드 3자리
[ERROR] - 로그 레벨
print - 그냥 찍어본거
153 - 인자1
55 - 인자2
asdfasdf - 인자3
간단하죠? 이젠 소스를 조금 살펴보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #include "mainwindow.h" #include "ui_mainwindow.h" // [디자인패턴] 싱글턴 패턴 사용을 위한 전방 선언 bool LogSingleton::destroyed = false; LogSingleton* LogSingleton::pInst = 0; // 메인 시작 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); LogSingleton::getInstance().SetDir("C:/"); LogSingleton::getInstance().SetLevel(LEVEL_WARNING); LogSingleton::getInstance().SetName("test"); LogSingleton::getInstance().SetDate("yyyyMMdd"); LogSingleton::getInstance().SetTime("hhmmsszzz"); LogSingleton::getInstance().Print(LEVEL_ERROR, "print %d %d %s", 153, 55, "asdfasdf"); // 임시 버튼 이벤트, 싱글턴 패턴 connect(ui->btn_err_, &QPushButton::clicked, this, [=]() { LogSingleton::getInstance().Print(LEVEL_ERROR, "print %d %d %s", 153, 55, "asdfasdf"); }); connect(ui->btn_war_, &QPushButton::clicked, this, [=]() { LogSingleton::getInstance().Print(LEVEL_WARNING, "print %d %d %s", 153, 55, "asdfasdf"); }); connect(ui->btn_info_, &QPushButton::clicked, this, [=]() { LogSingleton::getInstance().Print(LEVEL_INFORMATION, "print %d %d %s", 153, 55, "asdfasdf"); }); } MainWindow::~MainWindow() { delete ui; } | cs |
뭐.. 특별한 건 없어요. 핵심적인 건 LogSingleton의 Set() 함수들입니다.
파일을 생성한 디렉터리와 로그 파일에 기록할 로그 레벨을 설정해야 합니다.
1 2 3 4 5 6 7 8 | #ifndef COMMON_H #define COMMON_H enum WriteLevel { LEVEL_ERROR = 0, LEVEL_WARNING, LEVEL_INFORMATION }; | cs |
저는 로그 레벨을 경고 단계까지 주었습니다.
그러면 INFORMATION에 해당하는 메시지는 디버그 창에만 뜨고, 실제 파일엔 쓰이지 않습니다. 나머진... 뭐 ... 그냥저냥 설정하면 되고요.
1 2 3 4 5 | LogSingleton::getInstance().SetDir("C:/"); LogSingleton::getInstance().SetLevel(LEVEL_WARNING); LogSingleton::getInstance().SetName("test"); LogSingleton::getInstance().SetDate("yyyyMMdd"); LogSingleton::getInstance().SetTime("hhmmsszzz"); | cs |
로그 파일은 LogFile 클래스에 존재하는데 아래처럼 되어 있어요.
실제로 이 코드를 사용하실 분들은 여기서 로그 파일의 스타일을 꾸미시면 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #ifndef LOGFILE_H #define LOGFILE_H #include <QDebug> #include <QString> #include <QDateTime> #include <QFile> #include <QTextStream> #include "Common.h" class LogFile // 디자인패턴, 싱글턴 패턴 { // Log 타입 struct status { QString dir; int level; QString name; QString date; QString time; }; public: LogFile(); private: typedef status Status; Status status_; public: // setter void Dir(const QString dir) { status_.dir.clear(); status_.dir.append(dir); } void Level(const int level) { status_.level = level; } void Name(const QString name) { status_.name.clear(); status_.name.append(name); } void Date(const QString date) { status_.date.clear(); status_.date.append(date); } void Time(const QString time) { status_.time.clear(); status_.time.append(time); } public: void Print(const int level, const QString msg); }; #endif // LOGFILE_H | cs |
typedef 키워드는 정말 마음에 들어요. 내 마음대로 주무를 수 있다는 것이 이토록 좋을 줄이야 ㅎㅎㅎ.
[Singleton design pattern Qt]
근데, 한 가지 문제가 있습니다. Qt 5.3.2를 기준으로 C++11에서 지원하는 가변 인자 템플릿이 적용되질 않습니다. 인자의 수를 정해놓고 사용하는 데엔 문제가 없지만, 인자의 수를 정해놓지 않으면 에러가 발생하네요. (이거 때문에 디자인패턴 구성이 조금 망가짐)
아마도 5.3.2에서는 지원이 안 되나 봅니다. 저는 이런저런 시도를 해보았으나 자꾸 안되길래 접었어요. 이 부분에 대해서 아는 분들은 댓글이나 다른 포스트로 알려주시면 감사하겠습니다.
그래서, 어쩔 수 없이 C++에 C 코드를 넣었습니다. 아래처럼요.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <stdlib.h> /* for malloc, NULL, size_t */ #include <stdarg.h> /* for va_ stuff */ #include <string.h> /* for strcat et al. */ ..... ..... public: // 출력 메시지 전달 void Print(const int level, char* err, ... ) { char log_content[1024] = {0,}; va_list ap; va_start(ap, err); vsprintf_s(log_content + strlen(log_content), 1024, err, ap); va_end(ap); log_file_->Print(level, log_content); } | cs |
C언어에서는 가변인자를 이용할 수 있도록 va_list란 함수를 제공합니다. 소스는 간단해요.
필요에 따라 2개, 또는 3개의 헤더 파일을 인클루드하고, 위에 나온 소스를 그대로 사용하시면 됩니다. 이렇게 사용하시면, 인자의 개수에 상관없이 Print() 함수를 이용할 수 있어요. 개발자에도 유용한 함수죠.
[[Singleton design pattern Qt] 디자인패턴] 싱글톤 패턴 개념
마지막으로 싱글톤 패턴, 디자인패턴 구현 소스.
저는 여기서 참조 했습니다(C++에서 싱글톤 패턴 구현하기 [링크]). 이글루스 gimmesilver란 분이 작성해 놓은 코드가 좋아서 그대로 사용했으니, 다른 분들도 참조해 보세요.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | #ifndef LOGSINGLETON_H /* 디자인패턴 클래스 */ #define LOGSINGLETON_H #include <QDebug> #include <stdio.h> #include <stdlib.h> /* for malloc, NULL, size_t */ #include <stdarg.h> /* for va_ stuff */ #include <string.h> /* for strcat et al. */ #include "logfile.h" #include "Common.h" class LogSingleton { // 싱글턴 패턴 public: static LogSingleton &getInstance() { if (destroyed) { new(pInst) LogSingleton; // 2) atexit(killSingleton); destroyed = false; } else if (pInst == 0) { create(); } return *pInst; } private: LogSingleton() { log_file_ = new LogFile(); } LogSingleton(const LogSingleton & other); ~LogSingleton() { delete log_file_; destroyed = true; // 1) } static void create() { static LogSingleton inst; pInst = &inst; } static void killSingleton() { pInst->~LogSingleton(); // 3) } static bool destroyed; static LogSingleton *pInst; LogFile *log_file_; public: // 로그를 찍는 상태를 설정 void SetDir(const QString dir) { log_file_->Dir(dir);} void SetLevel(const int level) { log_file_->Level(level); } void SetName(const QString name) { log_file_->Name(name); } void SetDate(const QString date) { log_file_->Date(date); } void SetTime(const QString time) {log_file_->Time(time); } public: // 출력 메시지 전달 void Print(const int level, char* err, ... ) { char log_content[1024] = {0,}; va_list ap; va_start(ap, err); vsprintf_s(log_content + strlen(log_content), 1024, err, ap); va_end(ap); log_file_->Print(level, log_content); } }; #endif // LOGSINGLETON_H | cs |
잘 이해가 안 되는 부분은 댓글로 적어주세요.
[디자인패턴] Qt 싱글톤 패턴, 로그 생성 프로그램