/** * Tencent is pleased to support the open source community by making Tars available. * * Copyright (C) 2016THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * https://opensource.org/licenses/BSD-3-Clause * * Unless required by applicable law or agreed to in writing, software distributed * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ #include "LogImp.h" #include "servant/RemoteLogger.h" GlobeInfo g_globe; TC_DayLogger& GlobeInfo::makeDayLogger(const string &app, const string &server, const string &logname, const string &format,const string& ip) { string sLogPath = _log_path + "/" + app + "/" + server + "/" + logname; TLOGDEBUG("GlobeInfo::makeDayLogger sLogPath:" << sLogPath << "|format:" << format << endl); DLOG << "GlobeInfo::makeDayLogger sLogPath:" << sLogPath << "|format:" << format << endl; TC_DayLogger *p = new TC_DayLogger(); p->init(sLogPath, format); p->setupThread(&_group); //所有标识都不要 p->modFlag(0xffff, false); _loggers[logname][ip] = p; _formats[logname][ip] = format; return (*p); } TC_DayLogger& GlobeInfo::makeDayLogger(const LogInfo & info, const string &logname, const string &format,const string& ip) { string sLogPath = getRealLogName(info); //获取配置中的记录方式 string sFormat = format; string sLogType = info.sLogType; string sKey = info.appname + "." +info.servername + "." + info.sFilename; map::iterator it = _mLogType.find(sKey); if(it != _mLogType.end()) { //服务端的配置优先级最高 sLogType = it->second; //使用规范格式 sFormat = ""; } TLOGDEBUG("GlobeInfo::makeDayLogger sLogPath:" << sLogPath << "|app:" << info.appname << "|server:" << info.servername << "|filename:" << info.sFilename << "|format:" << format << "|setdivision:" << info.setdivision << "|bHasSufix:" << info.bHasSufix << "|bHasAppNamePrefix:" << info.bHasAppNamePrefix << "|sConcatStr" << info.sConcatStr << "|sSepar" << info.sSepar << "|sLogType:" << sLogType << endl); DLOG << "GlobeInfo::makeDayLogger sLogPath:" << sLogPath << "|app:" << info.appname << "|server:" << info.servername << "|filename:" << info.sFilename << "|format:" << format << "|setdivision:" << info.setdivision << "|bHasSufix:" << info.bHasSufix << "|bHasAppNamePrefix:" << info.bHasAppNamePrefix << "|sConcatStr" << info.sConcatStr << "|sSepar" << info.sSepar << "|sLogType:" << sLogType <init(sLogPath, format,info.bHasSufix,info.sConcatStr,getTarsLogType(sFormat,sLogType)); p->setSeparator(info.sSepar); p->enableSqareWrapper(info.bHasSquareBracket); p->setupThread(&_group); //所有标识都不要 p->modFlag(0xffff, false); _loggers[logname][ip] = p; _formats[logname][ip] = format; return (*p); } LogTypePtr GlobeInfo::getTarsLogType(const string& sFormat,const string& sCutType) { LogTypePtr logTypePtr = NULL; if(sCutType != "") { string sType = TC_Common::lower(sCutType); string::size_type pos = string::npos; if((pos = sType.find("day")) != string::npos) { int n = 1; if(sType.substr(0,pos) != "" && TC_Common::isdigit(sType.substr(0,pos)) == true) { n = TC_Common::strto(sType.substr(0,pos)); } string format = (sFormat=="") ? LogByDay::FORMAT : sFormat; logTypePtr = new LogByDay(format,n); } else if((pos = sType.find("hour")) != string::npos) { int n = 1; if(sType.substr(0,pos) != "" && TC_Common::isdigit(sType.substr(0,pos)) == true) { n = TC_Common::strto(sType.substr(0,pos)); } string format = (sFormat=="") ? LogByHour::FORMAT : sFormat; logTypePtr = new LogByHour(format,n); } else if((pos = sType.find("minute")) != string::npos) { int n = 10;//支持5,10分钟 if(sType.substr(0,pos) != "" && TC_Common::isdigit(sType.substr(0,pos)) == true) { n = TC_Common::strto(sType.substr(0,pos)); } string format = (sFormat=="") ? LogByMinute::FORMAT : sFormat; logTypePtr = new LogByMinute(format,n); } } return logTypePtr; } string GlobeInfo::getRealLogName(const LogInfo & info) { string sRealLogname; if(info.bHasAppNamePrefix) { sRealLogname = info.sFilename.empty() ? (info.appname +"." + info.servername) : \ (info.appname +"." + info.servername + info.sConcatStr + info.sFilename); } else { sRealLogname = info.sFilename; } string setDivision = getSetGoodFormat(info.setdivision); string sLogPath = _log_path + "/" + info.appname + "/" + setDivision + "/" + info.servername + "/" + sRealLogname; return sLogPath; } string GlobeInfo::getLogName(const LogInfo & info) { string sLogname = TC_Common::tostr(info.bHasSufix) + info.sConcatStr + TC_Common::tostr(info.bHasAppNamePrefix) + info.sConcatStr +\ TC_Common::tostr(info.bHasSquareBracket) + info.sConcatStr + info.sSepar + info.sConcatStr +\ info.setdivision + info.sConcatStr + info.appname + info.sConcatStr + info.servername + info.sConcatStr + info.sFilename + info.sConcatStr + info.sLogType; return sLogname; } bool GlobeInfo::HasSameFormat(const string& logname,const string& format,string& ip) { map::iterator itFormat = _formats[logname].begin(); bool bHasFormat = false; //是否有创建过的format for(; itFormat != _formats[logname].end(); itFormat++) { if(itFormat->second == format) //找到创建过的format { bHasFormat = true; ip = itFormat->first; //为创建过相同format的节点ip break; } } return bHasFormat; } bool GlobeInfo::IsLoggerAttached(const string& logname,const string& sExcludeIp,const TC_DayLogger* pLogger) { map::iterator itLogger = _loggers[logname].begin(); bool bIsAttached = false; //是否有ip在用该logger实例 for(; itLogger != _loggers[logname].end(); itLogger++) { if(itLogger->first != sExcludeIp && itLogger->second == pLogger) { bIsAttached = true; TLOGDEBUG("GlobeInfo::IsLoggerAttached first:" << itLogger->first<< endl); break; } } return bIsAttached; } TC_DayLogger& GlobeInfo::getLogger(const LogInfo & info,const string& ip) { string format = info.sFormat; if(binary_search(_vHourlist.begin(), _vHourlist.end(), (info.appname + "." + info.servername)) != false) { format = "%Y%m%d%H"; } string setDivision = getSetGoodFormat(info.setdivision); if(!TC_File::isFileExistEx((_log_path + "/" + info.appname + "/" + setDivision + "/" + info.servername), S_IFDIR)) { TC_File::makeDirRecursive(_log_path + "/" + info.appname + "/" + setDivision + "/" + info.servername); } string logname = getLogName(info); TLOGDEBUG("GlobeInfo::getLogger logname:" << logname << "|format:" << format << "|setDivision:" << setDivision << endl); Lock lock(*this); map >::iterator itLogName = _loggers.find(logname); if( itLogName == _loggers.end()) //没有创建过的log { return makeDayLogger(info, logname, format, ip); } map::iterator itIp = itLogName->second.find(ip); if(itIp == itLogName->second.end()) //没有创建过的ip节点 { string sSameIp(""); if(HasSameFormat(logname,format,sSameIp)) //有创建过的format,把新的节点ip划分到同组 { _loggers[logname][ip] = _loggers[logname][sSameIp];//使用具有相同format的logger实例 _formats[logname][ip] = format; return (*(_loggers[logname][ip])); } else //没有创建过该format,新建立一个logname下的format组 { return makeDayLogger(info, logname, format,ip); } } else //该logname下的这个ip节点创建过 { if(_formats[logname][ip] != format) //该ip节点的日志格式变化了 { string sSameIp(""); TC_DayLogger* pOldLogger = _loggers[logname][ip]; if(HasSameFormat(logname,format,sSameIp))//已经有该格式,归入同组 { _loggers[logname][ip] = _loggers[logname][sSameIp]; _formats[logname][ip] = format; if(pOldLogger) //删除旧的loger { pOldLogger->unSetupThread(); delete pOldLogger; pOldLogger = NULL; } return (*(_loggers[logname][ip])); } else { _loggers[logname][ip] = NULL; _formats[logname][ip] = ""; if(!IsLoggerAttached(logname,ip,pOldLogger))//可能有多个节点引用这个loger,这里需要判断 { pOldLogger->unSetupThread(); delete pOldLogger; pOldLogger = NULL; } return makeDayLogger(info, logname, format,ip); } } } //没有改变格式 return (*(_loggers[logname][ip])); } TC_DayLogger& GlobeInfo::getLogger(const string &app, const string &server, const string &file, const string &sformat,const string& ip) { if(!TC_File::isFileExistEx((_log_path + "/" + app + "/" + server), S_IFDIR)) { TC_File::makeDirRecursive(_log_path + "/" + app + "/" + server); } string format = sformat; if(binary_search(_vHourlist.begin(),_vHourlist.end(),(app + "." + server)) != false) { format = "%Y%m%d%H"; } string logname = file.empty() ? (app + "." + server) : (app + "." + server + "_" + file); TLOGDEBUG("GlobeInfo::getLogger logname:" << logname << "|format:" << format << endl); Lock lock(*this); map >::iterator itLogName = _loggers.find(logname); if( itLogName == _loggers.end()) //没有创建过的log { return makeDayLogger(app, server, logname, format,ip); } map::iterator itIp = itLogName->second.find(ip); if(itIp == itLogName->second.end()) //没有创建过的ip节点 { string sSameIp(""); if(HasSameFormat(logname,format,sSameIp)) //有创建过的format,把新的节点ip划分到同组 { _loggers[logname][ip] = _loggers[logname][sSameIp];//使用具有相同format的logger实例 _formats[logname][ip] = format; return (*(_loggers[logname][ip])); } else //没有创建过该format,新建立一个logname下的format组 { return makeDayLogger(app, server, logname, format,ip); } } else //该logname下的这个ip节点创建过 { if(_formats[logname][ip] != format) //该ip节点的日志格式变化了 { string sSameIp(""); TC_DayLogger* pOldLogger = _loggers[logname][ip]; if(HasSameFormat(logname,format,sSameIp))//已经有该格式,归入同组 { _loggers[logname][ip] = _loggers[logname][sSameIp]; _formats[logname][ip] = format; if(pOldLogger) //删除旧的loger { pOldLogger->unSetupThread(); delete pOldLogger; pOldLogger = NULL; } return (*(_loggers[logname][ip])); } else { _loggers[logname][ip] = NULL; _formats[logname][ip] = ""; if(!IsLoggerAttached(logname,ip,pOldLogger))//可能有多个节点引用这个loger,这里需要判断 { pOldLogger->unSetupThread(); delete pOldLogger; pOldLogger = NULL; } return makeDayLogger(app, server, logname, format,ip); } } } //没有改变格式 return (*(_loggers[logname][ip])); } string GlobeInfo::getSetGoodFormat(const string& sSetDivision) { vector vtSetDivisions = TC_Common::sepstr(sSetDivision,"."); if(vtSetDivisions.size() != 3) { return ""; } else { if(vtSetDivisions[2] == "*") { return string(vtSetDivisions[0] + vtSetDivisions[1]); } else { return string(vtSetDivisions[0] + vtSetDivisions[1] + vtSetDivisions[2]); } } } void GlobeInfo::update(const vector &vHourlist, const map &mLogType) { Lock lock(*this); _vHourlist = vHourlist; _mLogType = mLogType; } ////////////////////////////////////////// // void LogImp::initialize() { } void LogImp::logger(const string &app, const string &server, const string &file, const string &format, const vector &buffer, tars::TarsCurrentPtr current) { LOG_CONSOLE_DEBUG << app << ", " << server << ", " << file << ", " << format << endl; TC_DayLogger &dl = g_globe.getLogger(app, server, file, format,current->getIp()); //记录日志 for(size_t i = 0; i < buffer.size(); i++) { if(g_globe._bIpPrefix) { dl.any() << current->getIp() << "|" << buffer[i]; } else { dl.any() << buffer[i]; } } } void LogImp::loggerbyInfo(const LogInfo & info,const vector & buffer,tars::TarsCurrentPtr current) { LOG_CONSOLE_DEBUG << info.writeToJsonString() << endl; TC_DayLogger &dl = g_globe.getLogger(info,current->getIp()); //记录日志 for(size_t i = 0; i < buffer.size(); i++) { if(g_globe._bIpPrefix) { dl.any() << current->getIp() << info.sSepar << buffer[i]; } else { dl.any() << buffer[i]; } } }