Problem
In this question you will implement some features of a hypothetical [i]message logging[/i] class.
There is no one correct answer to this question – it is a chance for you to demonstrate your ability to write good C++/Java.
The message logging class will be used within an application to log progress messages as the application runs.
Messages have different levels as follows:
1 = Error, 2 = Warning, 3 = Information, 4 = Debug, 5 = Trace
You have been provided with the following class definition to start you off.
You may change the data types being used if that helps the implementation.
Solution
#include <iostream>
#include <string>
#include <fstream>
#include <crtdbg.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
using namespace std;
class MessageLogger
{
public:
MessageLogger();
~MessageLogger();
public:
int addMessage(int messageLevel, const string& message);
bool getNextMessage(time_t& when, int& messageLevel, string& message);
enum{Error = 1, Warning, Information, Debug, Trace};
private:
char *createFileName(time_t &when);
char *createTimeInfo(time_t &when);
char *createLevelInfo(int msgLevel);
int writeTimeInfo(time_t &when, FILE *fd);
int writeLevelInfo(int level, FILE *fd);
int writeMessage(char *msg, FILE *fd);
int parseLine(char *line, int& year, int& mon, int& day, int& hour, int& min, char *level, char *msg);
int convertTime(time_t &when, int& year, int& mon, int& day, int& hour, int& min);
int convertLevel2Int(char *str);
int getFileInfo(char *filename);
FILE *_fd;
long _pos[5];
};
MessageLogger::MessageLogger()
{
_pos[0] = 0;
_pos[1] = 0;
_pos[2] = 0;
_pos[3] = 0;
_pos[4] = 0;
}
MessageLogger::~MessageLogger()
{
}
char *MessageLogger::createFileName(time_t &when)
{
static char buf[256];
struct tm tmStruct;
gmtime_s(&tmStruct, &when);
int year = tmStruct.tm_year + 1900;
int mon = tmStruct.tm_mon + 1;
int day = tmStruct.tm_mday;
sprintf(buf, "log-%d-%d-%d.txt", year, mon, day);
return buf;
}
char *MessageLogger::createTimeInfo(time_t &when)
{
static char buf[256];
struct tm tmStruct;
gmtime_s(&tmStruct, &when);
int year = tmStruct.tm_year + 1900;
int mon = tmStruct.tm_mon + 1;
int day = tmStruct.tm_mday;
int hour = tmStruct.tm_hour;
int min = tmStruct.tm_min;
sprintf(buf, "%4d-%2d-%2d\t%2d:%2d", year, mon, day, hour, min);
return buf;
}
char *MessageLogger::createLevelInfo(int msgLevel)
{
switch(msgLevel){
case MessageLogger::Error:
return "Error";
case MessageLogger::Warning:
return "Warning";
case MessageLogger::Information:
return "Information";
case MessageLogger::Debug:
return "Debug";
case MessageLogger::Trace:
return "Trace";
default:
return "Unknown";
}
}
int MessageLogger::convertLevel2Int(char *level)
{
if(strcmp(level,"Error")==0)
return MessageLogger::Error;
else if(strcmp(level,"Warning")==0)
return MessageLogger::Warning;
else if(strcmp(level,"Information")==0)
return MessageLogger::Information;
else if(strcmp(level,"Debug")==0)
return MessageLogger::Debug;
else if(strcmp(level,"Trace")==0)
return MessageLogger::Trace;
else
return -1;
}
int MessageLogger::writeTimeInfo(time_t &when, FILE *fd)
{
fwrite(createTimeInfo(when),strlen(createTimeInfo(when)), 1, fd);
fputc('\t',fd);
return 1;
}
int MessageLogger::writeLevelInfo(int level, FILE *fd)
{
fwrite(createLevelInfo(level),strlen(createLevelInfo(level)),1,fd);
fputc('\t',fd);
return 1;
}
int MessageLogger::writeMessage(char *msg, FILE *fd)
{
fwrite(msg, strlen(msg), 1, fd);
fputc('\n',fd);
return 1;
}
int MessageLogger::parseLine(char *line, int& year, int& mon, int& day, int& hour, int& min, char *level, char *msg)
{
int num;
num = sscanf(line, "%4d-%2d-%2d\t%2d:%2d\t%s\t%s", &year, &mon, &day, &hour, &min, level, msg);
return (num == 7)? 1:0;
}
int MessageLogger::getFileInfo(char *filename)
{
struct _stat statBuf;
int result;
errno_t err;
result = _stat( filename, &statBuf);
if(!result == 0){
if(errno == ENOENT){
return 1;
}
else{
return 0;
}
}
else{
return 2;
}
}
int MessageLogger::convertTime(time_t &when, int& year, int& mon, int& day, int& hour, int& min)
{
struct tm tmStruct;
gmtime_s(&tmStruct, &when);
year = tmStruct.tm_year + 1900;
mon = tmStruct.tm_mon + 1;
day = tmStruct.tm_mday;
hour = tmStruct.tm_hour;
min = tmStruct.tm_min;
return 1;
}
int MessageLogger::addMessage(int messageLevel, const string& message)
{
if(messageLevel < 0 || messageLevel > 5){
cerr << "Message level should be in the range of [1..5]" << endl;
return 0;
}
// Get current time
time_t now;
time(&now);
if(getFileInfo(createFileName(now)) == 0){
return 0;
}
else if(getFileInfo(createFileName(now)) == 1){
_fd = fopen(createFileName(now),"w");
if(_fd == NULL){
cerr << "Open file failed in addMessage" << endl;
return 0;
}
}
else{
_fd = fopen(createFileName(now),"a");
if(_fd == NULL){
cerr << "Open file failed in addMessage" << endl;
return 0;
}
}
writeTimeInfo(now, _fd);
writeLevelInfo(messageLevel,_fd);
writeMessage((char *)message.c_str(), _fd);
fclose(_fd);
return 1;
}
bool MessageLogger::getNextMessage(time_t& when, int& messageLevel, string& message)
{
char line[256];
int year, mon, day, hour, min;
char level[20];
char msg[256];
int year1, mon1, day1, hour1, min1;
if(getFileInfo(createFileName(when)) != 0){
_fd = fopen(createFileName(when),"r");
if(_fd == NULL){
cerr << "Open file failed in getNextMessage" << endl;
return 0;
}
fseek(_fd, _pos[messageLevel - 1], SEEK_SET);
while(!feof(_fd)){
fgets(line, 256, _fd);
parseLine(line, year, mon, day, hour, min, level, msg);
convertTime(when, year1, mon1, day1, hour1, min1);
if(hour1 == hour && min1 == min && messageLevel == convertLevel2Int(level)){
cout << createTimeInfo(when) << '\t' << level << "\t"<< msg << "\tis found!" << endl;
_pos[messageLevel - 1] = ftell(_fd);
break;
}
}
fclose(_fd);
return true;
}
return false;
}
int main(int argc, char *argv[])
{
MessageLogger ml;
string msg;
ml.addMessage(MessageLogger::Debug, "1Debuging infomation 1");
ml.addMessage(MessageLogger::Debug, "2Debuging infomation 2");
ml.addMessage(MessageLogger::Error, "Error infomation");
ml.addMessage(MessageLogger::Warning, "Warning infomation");
time_t now;
time(&now);
int msgLevel = MessageLogger::Debug;
ml.getNextMessage(now, msgLevel, msg);
msgLevel = MessageLogger::Error;
ml.getNextMessage(now, msgLevel, msg);
msgLevel = MessageLogger::Debug;
ml.getNextMessage(now, msgLevel, msg);
cout << msg << endl;
return 0;
}