00001
00006 #include <ctime>
00007 #include <sstream>
00008 #include <iostream>
00009 #include <errno.h>
00010 #include <sys/stat.h>
00011 #include <sys/types.h>
00012 #include <csignal>
00013 #include <cstring>
00014
00015 #include "Logger.h"
00016 #include "Cache.h"
00017 #include "functions.h"
00018
00019 bool Logger::stop = 0;
00020
00021 Log::Log(logType type, const string& firstSParam, const string& secondSParam, unsigned firstUParam,
00022 unsigned secondUParam) :
00023 type(type), firstSParam(firstSParam), secondSParam(secondSParam), firstUParam(firstUParam), secondUParam(
00024 secondUParam) {
00025 time = Cache::getCurrentTime();
00026 }
00027
00028 Logger::Logger() :
00029 bufferLength(2000), interval(3), logLevel(3), dumpToFile(0), threadID(0) {
00030 output = NULL;
00031 }
00032
00033 Logger::~Logger() {
00034
00035 if (threadID) {
00036
00037 pthread_kill(threadID, SIGUSR1);
00038 pthread_join(threadID, NULL);
00039 threadID = 0;
00040
00041 }
00042
00043 saveLogs();
00044 if (dumpToFile) {
00045 delete output;
00046 }
00047 }
00048
00049 void Logger::operator()() {
00050
00051 cout << "Logger: logging thread started" << endl;
00052
00053 while (!stop) {
00054 saveLogs();
00055 usleep(1000 * interval);
00056 }
00057
00058 }
00059
00060 void Logger::setParameters(Settings config) {
00061
00062 bool logDirectoryChange = directory != config.logDirectory;
00063
00064 bufferLength = config.logBufferLength;
00065 interval = config.logInterval;
00066 logLevel = config.logLevel;
00067 directory = config.logDirectory;
00068
00069 ostringstream s;
00070
00071 s << "gcInterval: " << config.GCInterval << " logBufferLength = " << bufferLength << " logInterval = " << interval
00072 << " logLevel = " << logLevel;
00073
00074 if (isNotFullAndSatisfactoryLevel(logTypeLevel[SET_PARAMETERS])) {
00075 push(Log(SET_PARAMETERS, s.str(), "", 0, 0));
00076 }
00077
00078 if (!logLevel) {
00079
00080 if (threadID) {
00081
00082 pthread_kill(threadID, SIGUSR1);
00083 pthread_join(threadID, NULL);
00084 threadID = 0;
00085
00086 }
00087
00088 cout << "Logger:\tnot logging anything - log level is 0" << endl;
00089 return;
00090 }
00091
00092 if (logDirectoryChange) {
00093
00094 MUTEX_LOCK(mutex);
00095
00096 if (dumpToFile) {
00097 delete output;
00098 }
00099
00100 dumpToFile = true;
00101
00102 if (mkdir(directory.c_str(), S_IREAD | S_IWRITE | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH) == -1) {
00103 if (errno != EEXIST) {
00104 dumpToFile = false;
00105 }
00106 }
00107
00108 if (dumpToFile) {
00109
00110 time_t now = time(NULL);
00111 struct tm *ts;
00112 ts = localtime(&now);
00113 char buf[80];
00114
00115 strftime(buf, sizeof(buf), "%Y-%m-%d_%H.%M.%S.log", ts);
00116
00117 fileName = directory + "/" + getPackageName() + "_";
00118 fileName += buf;
00119
00120 ofstream * of = new ofstream(fileName.c_str(), ios::out);
00121
00122 if (of) {
00123 output = of;
00124 cout << "Logger: current log file: '" << fileName << "'" << endl;
00125 } else {
00126 dumpToFile = false;
00127 }
00128
00129 }
00130
00131 if (!dumpToFile) {
00132 cout << "Logger: sending logs to STDOUT" << endl;
00133 output = &cout;
00134 }
00135
00136 MUTEX_UNLOCK(mutex);
00137
00138 }
00139
00140 if (!threadID) {
00141 stop = false;
00142 int ret;
00143 if ((ret = pthread_create(&threadID, NULL, loggerThread, this))) {
00144 fprintf(stderr, "Server:\tduring starting logger: pthread_create: %s\n", strerror(ret));
00145 }
00146 }
00147
00148 }
00149
00150 void Logger::saveLogs() {
00151
00152 char timeBuffer[20];
00153
00154 MUTEX_LOCK(mutex);
00155 queue<Log> copy = logBuffer;
00156 while (!logBuffer.empty()) {
00157 logBuffer.pop();
00158 }
00159 MUTEX_UNLOCK(mutex);
00160
00161 while (!copy.empty()) {
00162
00163 Log & log = copy.front();
00164
00165 strftime(timeBuffer, 20, "%b %d %X ", localtime(&log.time));
00166 *output << timeBuffer;
00167
00168 switch (log.type) {
00169 case GET:
00170 *output << "GET KEY:" << log.firstSParam.c_str() << " SPACE:" << log.secondSParam.c_str() << "\n";
00171 break;
00172 case SET:
00173 *output << "SET KEY:" << log.firstSParam.c_str() << " SPACE:" << log.secondSParam.c_str() << " TIMEOUT: "
00174 << log.firstUParam << "\n";
00175 break;
00176 case SET_NUMERIC:
00177 *output << "SET NUMERIC KEY:" << log.firstSParam.c_str() << " SPACE:" << log.secondSParam.c_str()
00178 << " TIMEOUT: " << log.firstUParam << "\n";
00179 break;
00180 case INCREMENT:
00181 *output << "INCREMENT KEY:" << log.firstSParam.c_str() << " SPACE:" << log.secondSParam.c_str()
00182 << " STEP: " << log.firstUParam << " TIMEOUT: " << log.secondUParam << "\n";
00183 break;
00184 case SAVE_SPACE:
00185 *output << "SAVE SPACE:" << log.firstSParam.c_str() << " FILE:" << log.secondSParam.c_str() << "\n";
00186 break;
00187 case LOAD_SPACE:
00188 *output << "LOAD SPACE:" << log.firstSParam.c_str() << " FILE:" << log.secondSParam.c_str() << "\n";
00189 break;
00190 case DESTROY_SPACE:
00191 *output << "DESTROY SPACE:" << log.firstSParam.c_str() << "\n";
00192 break;
00193 case CREATE_SPACE:
00194 *output << "CREATE SPACE:" << log.firstSParam.c_str() << " USERNAME: " << log.secondSParam.c_str()
00195 << " SOFT QUOTA:" << log.firstUParam << " HARD QUOTA:" << log.secondUParam << "\n";
00196 break;
00197 case CLEAN_SPACE:
00198 *output << "CLEAN SPACE:" << log.firstSParam.c_str() << "\n";
00199 break;
00200 case SELECT_SPACE:
00201 *output << "SELECT SPACE:" << log.firstSParam.c_str() << "\n";
00202 break;
00203 case INITIALIZE:
00204 *output << "INITIALIZE\n";
00205 break;
00206 case FINALIZE:
00207 *output << "FINALIZE\n";
00208 break;
00209 case LOGIN:
00210 *output << "LOGIN USER:" << log.firstSParam.c_str() << "\n";
00211 break;
00212 case SOFT_QUOTA_EXCEEDED:
00213 *output << "SOFT QUOTA EXCEEDED SPACE:" << log.firstSParam.c_str() << "\n";
00214 break;
00215 case HARD_QUOTA_REACHED:
00216 *output << "HARD QUOTA REACHED SPACE:" << log.firstSParam.c_str() << "\n";
00217 break;
00218 case LRU_ENTRY_REMOVED:
00219 *output << "LRU ENTRY REMOVED KEY:" << log.firstSParam.c_str() << " SPACE:" << log.secondSParam.c_str()
00220 << "\n";
00221 break;
00222 case ENTRY_TIMED_OUT:
00223 *output << "ENTRY TIMED OUT KEY:" << log.firstSParam.c_str() << " SPACE:" << log.secondSParam.c_str()
00224 << "\n";
00225 break;
00226 case QUOTA_USED_BY_USER:
00227 *output << "QUOTA USED BY USER:" << log.firstSParam.c_str() << " QUOTA:" << log.firstUParam << "\n";
00228 break;
00229 case QUOTA_USED_BY_SPACE:
00230 *output << "QUOTA USED BY SPACE:" << log.firstSParam.c_str() << " QUOTA:" << log.firstUParam << "\n";
00231 break;
00232 case BUFFER_OVERFLOW:
00233 *output << "LOGGER BUFFER OVERFLOW\n";
00234 break;
00235 case LOAD_CONFIG:
00236 *output << "CONFIGURATION LOADED FROM DIRECTORY: " << log.firstSParam.c_str() << " LOG LEVEL SWITCHED TO: "
00237 << log.firstUParam << "\n";
00238 break;
00239 case ERROR:
00240 *output << "ERROR OCCURED: " << log.firstSParam.c_str() << "\n";
00241 break;
00242 case CLEAR_STATS:
00243 *output << "CLEAR STATS: " << log.firstSParam.c_str() << "\n";
00244 break;
00245 case GC_START_RUN:
00246 *output << "GC START RUN\n";
00247 break;
00248 case GC_END_RUN:
00249 *output << "GC END RUN\n";
00250 break;
00251 case GC_START_COLLECTING_FROM_SPACE:
00252 *output << "GC START COLLECTING FROM SPACE: " << log.firstSParam.c_str() << "\n";
00253 break;
00254 case SET_PARAMETERS:
00255 *output << "NEW CONFIG READ: " << log.firstSParam.c_str() << "\n";
00256 break;
00257 case GC_WALK:
00258 *output << "GC FINISHED ROUND: " << log.firstSParam.c_str() << "\n";
00259 break;
00260 case TIME_RECORD:
00261 *output << "NEW RECORD OF '" << log.firstSParam.c_str() << "' --> " << log.firstUParam << "\n";
00262 break;
00263 }
00264
00265 output->flush();
00266
00267 copy.pop();
00268
00269 }
00270 }
00271
00272 void Logger::push(Log log) {
00273 MUTEX_LOCK(mutex);
00274 logBuffer.push(log);
00275 MUTEX_UNLOCK(mutex);
00276 }
00277
00278 bool Logger::isNotFullAndSatisfactoryLevel(int level) {
00279 if (level > logLevel)
00280 return false;
00281 if (bufferLength == 0)
00282 return true;
00283
00284 if (logBuffer.size() == bufferLength)
00285 logBuffer.push(Log(BUFFER_OVERFLOW, "", "", 0, 0));
00286 return (logBuffer.size() < bufferLength);
00287 }
00288
00289 void Logger::logBufferOverflow() {
00290 if (isNotFullAndSatisfactoryLevel(logTypeLevel[BUFFER_OVERFLOW]))
00291 push(Log(BUFFER_OVERFLOW, "", "", 0, 0));
00292 }
00293
00294 void Logger::logGet(const string& key, const string& spaceName) {
00295 if (isNotFullAndSatisfactoryLevel(logTypeLevel[GET]))
00296 push(Log(GET, key, spaceName, 0, 0));
00297 }
00298
00299 void Logger::logSet(const string& key, const string& spaceName, unsigned timeout) {
00300 if (isNotFullAndSatisfactoryLevel(logTypeLevel[SET]))
00301 push(Log(SET, key, spaceName, timeout, 0));
00302 }
00303
00304 void Logger::logSetNumeric(const string& key, const string& spaceName, unsigned timeout) {
00305 if (isNotFullAndSatisfactoryLevel(logTypeLevel[SET_NUMERIC]))
00306 push(Log(SET_NUMERIC, key, spaceName, timeout, 0));
00307 }
00308
00309 void Logger::logIncrement(const string& key, const string& spaceName, unsigned step, unsigned timeout) {
00310 if (isNotFullAndSatisfactoryLevel(logTypeLevel[INCREMENT]))
00311 push(Log(INCREMENT, key, spaceName, step, timeout));
00312 }
00313
00314 void Logger::logSaveSpace(const string& spaceName, const string& fileName) {
00315 if (isNotFullAndSatisfactoryLevel(logTypeLevel[SAVE_SPACE]))
00316 push(Log(SAVE_SPACE, spaceName, fileName, 0, 0));
00317 }
00318
00319 void Logger::logLoadSpace(const string& spaceName, const string& fileName) {
00320 if (isNotFullAndSatisfactoryLevel(logTypeLevel[LOAD_SPACE]))
00321 push(Log(LOAD_SPACE, spaceName, fileName, 0, 0));
00322 }
00323
00324 void Logger::logDestroySpace(const string& spaceName) {
00325 if (isNotFullAndSatisfactoryLevel(logTypeLevel[DESTROY_SPACE]))
00326 push(Log(DESTROY_SPACE, spaceName, "", 0, 0));
00327 }
00328
00329 void Logger::logCreateSpace(const string& spaceName, const string& userName, unsigned softQuota, unsigned hardQuota) {
00330 if (isNotFullAndSatisfactoryLevel(logTypeLevel[CREATE_SPACE]))
00331 push(Log(CREATE_SPACE, spaceName, userName, softQuota, hardQuota));
00332 }
00333
00334 void Logger::logCleanSpace(const string& spaceName) {
00335 if (isNotFullAndSatisfactoryLevel(logTypeLevel[CLEAN_SPACE]))
00336 push(Log(CLEAN_SPACE, spaceName, "", 0, 0));
00337 }
00338
00339 void Logger::logSelectSpace(const string& spaceName) {
00340 if (isNotFullAndSatisfactoryLevel(logTypeLevel[SELECT_SPACE]))
00341 push(Log(SELECT_SPACE, spaceName, "", 0, 0));
00342 }
00343
00344 void Logger::logInitialize() {
00345 if (isNotFullAndSatisfactoryLevel(logTypeLevel[INITIALIZE]))
00346 push(Log(INITIALIZE, "", "", 0, 0));
00347 }
00348
00349 void Logger::logFinalize() {
00350 if (isNotFullAndSatisfactoryLevel(logTypeLevel[FINALIZE]))
00351 push(Log(FINALIZE, "", "", 0, 0));
00352 }
00353
00354 void Logger::logLogin(const string& userName) {
00355 if (isNotFullAndSatisfactoryLevel(logTypeLevel[LOGIN]))
00356 push(Log(LOGIN, userName, "", 0, 0));
00357 }
00358
00359 void Logger::logSoftQuotaExceeded(const string& spaceName) {
00360 if (isNotFullAndSatisfactoryLevel(logTypeLevel[SOFT_QUOTA_EXCEEDED]))
00361 push(Log(SOFT_QUOTA_EXCEEDED, spaceName, "", 0, 0));
00362 }
00363
00364 void Logger::logHardQuotaReached(const string& spaceName) {
00365 if (isNotFullAndSatisfactoryLevel(logTypeLevel[HARD_QUOTA_REACHED]))
00366 push(Log(HARD_QUOTA_REACHED, spaceName, "", 0, 0));
00367 }
00368
00369 void Logger::logLRUEntryRemoved(const string& key, const string& spaceName) {
00370 if (isNotFullAndSatisfactoryLevel(logTypeLevel[LRU_ENTRY_REMOVED]))
00371 push(Log(LRU_ENTRY_REMOVED, key, spaceName, 0, 0));
00372 }
00373
00374 void Logger::logEntryTimedOut(const string& key, const string& spaceName) {
00375 if (isNotFullAndSatisfactoryLevel(logTypeLevel[ENTRY_TIMED_OUT]))
00376 push(Log(ENTRY_TIMED_OUT, key, spaceName, 0, 0));
00377 }
00378
00379 void Logger::logQuotaUsedByUser(const string& userName, unsigned quota) {
00380 if (isNotFullAndSatisfactoryLevel(logTypeLevel[QUOTA_USED_BY_USER]))
00381 push(Log(QUOTA_USED_BY_USER, userName, "", quota, 0));
00382 }
00383
00384 void Logger::logQuotaUsedBySpace(const string& spaceName, unsigned quota) {
00385 if (isNotFullAndSatisfactoryLevel(logTypeLevel[QUOTA_USED_BY_SPACE]))
00386 push(Log(QUOTA_USED_BY_SPACE, spaceName, "", quota, 0));
00387 }
00388
00389 void Logger::logLoadConfig(const string& confDir, unsigned logLevel) {
00390 if (isNotFullAndSatisfactoryLevel(logTypeLevel[LOAD_CONFIG]))
00391 push(Log(LOAD_CONFIG, confDir, "", logLevel, 0));
00392 }
00393
00394 void Logger::logError(const string& error) {
00395 if (isNotFullAndSatisfactoryLevel(logTypeLevel[ERROR]))
00396 push(Log(ERROR, error, "", 0, 0));
00397 }
00398
00399 void Logger::logClearStats(const string &spaceName) {
00400 if (isNotFullAndSatisfactoryLevel(logTypeLevel[CLEAR_STATS]))
00401 push(Log(CLEAR_STATS, spaceName, "", 0, 0));
00402 }
00403
00404 void Logger::logGCStartRun() {
00405 if (isNotFullAndSatisfactoryLevel(logTypeLevel[GC_START_RUN]))
00406 push(Log(GC_START_RUN, "", "", 0, 0));
00407 }
00408
00409 void Logger::logGCEndRun() {
00410 if (isNotFullAndSatisfactoryLevel(logTypeLevel[GC_END_RUN]))
00411 push(Log(GC_END_RUN, "", "", 0, 0));
00412 }
00413
00414 void Logger::logGCStartCollectingFromSpace(const string &spaceName) {
00415 if (isNotFullAndSatisfactoryLevel(logTypeLevel[GC_START_COLLECTING_FROM_SPACE]))
00416 push(Log(GC_START_COLLECTING_FROM_SPACE, spaceName, "", 0, 0));
00417 }
00418
00419 void Logger::logGCWalk(const string & message) {
00420 if (isNotFullAndSatisfactoryLevel(logTypeLevel[GC_WALK])) {
00421 push(Log(GC_WALK, message, "", 0, 0));
00422 }
00423 }
00424
00425 void Logger::logTimeRecord(const string & discipline, unsigned int miliseconds) {
00426 if (isNotFullAndSatisfactoryLevel(logTypeLevel[TIME_RECORD])) {
00427 push(Log(TIME_RECORD, discipline, "", miliseconds, 0));
00428 }
00429 }
00430
00431 void * loggerThread(void * arg) {
00432
00433 Logger::stop = false;
00434
00435 struct sigaction action;
00436
00437 action.sa_handler = loggerHandler;
00438 sigemptyset(&action.sa_mask);
00439 action.sa_flags = SA_NOCLDSTOP;
00440
00441 if (sigaction(SIGUSR1, &action, NULL) < 0) {
00442 perror("sigaction");
00443 }
00444
00445 Logger * l = (Logger *) arg;
00446
00447 l->operator ()();
00448
00449 return NULL;
00450
00451 }
00452
00453 void loggerHandler(int n) {
00454 Logger::stop = true;
00455 }