/************************************************************************* * UrBackup - Client/Server backup system * Copyright (C) 2011-2016 Martin Raiber * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . **************************************************************************/ #include "server_log.h" #include "../stringtools.h" #include "../Interface/Database.h" #include "../Interface/Query.h" #include "database.h" #include "../stringtools.h" #include std::map ServerLogger::logdata; IMutex *ServerLogger::mutex=NULL; std::map ServerLogger::circular_logdata; logid_t ServerLogger::logid_gen; std::map ServerLogger::logid_client; const size_t circular_logdata_buffersize=20; const size_t max_memory_logdata_size = 2 * 1024 * 1024; void ServerLogger::Log(logid_t logid, const std::string &pStr, int LogLevel) { Server->Log(pStr, LogLevel); IScopedLock lock(mutex); logCircular(logid_client[logid], logid, pStr, LogLevel); if(LogLevel<0) return; logMemory(Server->getTimeSeconds(), logid, pStr, LogLevel); } void ServerLogger::Log(int64 times, logid_t logid, const std::string &pStr, int LogLevel) { Server->Log(pStr, LogLevel); IScopedLock lock(mutex); logCircular(logid_client[logid], logid, pStr, LogLevel); if(LogLevel<0) return; logMemory(times, logid, pStr, LogLevel); } void ServerLogger::logMemory(int64 times, logid_t logid, const std::string &pStr, int LogLevel) { std::map::iterator it = logid_client.find(logid); if (it != logid_client.end() && it->second <= 0) { return; } SLogEntry le; le.data=pStr; le.loglevel=LogLevel; le.time=times; std::map::iterator iter=logdata.find(logid); size_t old_memory_used = 0; size_t new_memory_used; if( iter==logdata.end() ) { SLogData log_data; log_data.data.push_back(le); log_data.memory_used = logEntrySize(le); new_memory_used = log_data.memory_used; logdata.insert(std::pair(logid, log_data) ); } else { if (iter->second.memory_used >= max_memory_logdata_size) { return; } old_memory_used = iter->second.memory_used; iter->second.memory_used += logEntrySize(le); new_memory_used = iter->second.memory_used; iter->second.data.push_back(le); } if (old_memory_used < max_memory_logdata_size && new_memory_used >= max_memory_logdata_size) { SLogEntry le; le.data = "Max log size reached (" + PrettyPrintBytes(max_memory_logdata_size) + "). Not logging more."; le.loglevel = LL_WARNING; le.time = Server->getTimeSeconds(); logdata[logid].data.push_back(le); } } size_t ServerLogger::logEntrySize(const SLogEntry& entry) { //short string optimization on 64bit if (entry.data.size() > 22) { return sizeof(void*) + sizeof(SLogEntry) + entry.data.capacity(); } else { return sizeof(void*) + sizeof(SLogEntry); } } std::vector ServerLogger::stripLogIdFilter(const std::vector& data, logid_t logid) { std::vector ret; ret.reserve(data.size()); for (size_t i = 0; i < data.size(); ++i) { if (logid == logid_t() || logid == data[i].logid) { SCircularLogEntry ne; ne.id = data[i].id; ne.loglevel = data[i].loglevel; ne.time = data[i].time; ne.utf8_msg = data[i].utf8_msg; ret.push_back(ne); } } return ret; } void ServerLogger::logCircular(int clientid, logid_t logid, const std::string &pStr, int LogLevel) { std::map::iterator iter=circular_logdata.find(clientid); SCircularData *data; if(iter==circular_logdata.end()) { data=&circular_logdata[clientid]; data->data.resize(circular_logdata_buffersize); data->idx=0; data->id=1; } else { data=&iter->second; } SCircularLogEntryWithId& entry=data->data[data->idx]; entry.id=data->id++; entry.loglevel=LogLevel; entry.time=Server->getTimeSeconds(); entry.utf8_msg=pStr; entry.logid = logid; data->idx=(data->idx+1)%circular_logdata_buffersize; } void ServerLogger::init_mutex(void) { mutex=Server->createMutex(); } void ServerLogger::destroy_mutex(void) { Server->destroy(mutex); } std::string ServerLogger::getLogdata(logid_t logid, int &errors, int &warnings, int &infos) { IScopedLock lock(mutex); std::string ret; std::map::iterator iter=logdata.find(logid); if( iter!=logdata.end() ) { for(size_t i=0;isecond.data.size();++i) { SLogEntry &le=iter->second.data[i]; if(le.loglevel==LL_ERROR) ++errors; else if(le.loglevel==LL_WARNING) ++warnings; else if(le.loglevel==LL_INFO) ++infos; ret+=convert(le.loglevel); ret+="-"; ret+=convert(le.time); ret+="-"; ret+=(le.data); ret+="\n"; } return ret; } else { return ""; } } std::string ServerLogger::getWarningLevelTextLogdata(logid_t logid) { IScopedLock lock(mutex); std::string ret; std::map::iterator iter=logdata.find(logid); if( iter!=logdata.end() ) { for(size_t i=0;isecond.data.size();++i) { SLogEntry &le=iter->second.data[i]; if(le.loglevel>=LL_WARNING) { if(le.loglevel==LL_WARNING) ret+="WARNING: "; else if(le.loglevel==LL_ERROR) ret+="ERROR: "; ret+=le.data; ret+="\r\n"; } } return ret; } else { return ""; } } void ServerLogger::reset(logid_t id) { IScopedLock lock(mutex); std::map::iterator iter=logdata.find(id); if( iter!=logdata.end() ) { std::vector().swap(iter->second.data); iter->second.memory_used = 0; } } void ServerLogger::reset( int clientid ) { IScopedLock lock(mutex); for(std::map::iterator it=logid_client.begin(); it!=logid_client.end();++it) { if(it->second==clientid) { reset(it->first); } } } std::vector ServerLogger::getCircularLogdata( int clientid, size_t minid, logid_t logid) { IScopedLock lock(mutex); std::map::const_iterator iter=circular_logdata.find(clientid); if(iter!=circular_logdata.end()) { if(minid==std::string::npos) return stripLogIdFilter(iter->second.data, logid); for(size_t i=0;isecond.data.size();++i) { if (iter->second.data[i].id > minid && iter->second.data[i].id != std::string::npos && (logid == logid_t() || iter->second.data[i].logid == logid) ) { return stripLogIdFilter(iter->second.data, logid); } } return std::vector(); } else { if(minid==std::string::npos) { std::vector ret; SCircularLogEntry entry; entry.id=0; entry.loglevel=LL_INFO; entry.time=Server->getTimeSeconds(); entry.utf8_msg="No log entries yet"; ret.push_back(entry); return ret; } return std::vector(); } } logid_t ServerLogger::getLogId( int clientid ) { IScopedLock lock(mutex); logid_t ret= std::make_pair(++logid_gen.first, 0); logid_client[ret] = clientid; return ret; } bool ServerLogger::hasClient( logid_t id, int clientid ) { IScopedLock lock(mutex); return logid_client[id] == clientid; }