anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
logger.cpp (9989B)
1 /* Logging routines. 2 * 3 * (C) 2003-2022 Anope Team 4 * Contact us at team@anope.org 5 * 6 * Please read COPYING and README for further details. 7 * 8 * Based on the original code of Epona by Lara. 9 * Based on the original code of Services by Andy Church. 10 */ 11 12 #include "services.h" 13 #include "modules.h" 14 #include "commands.h" 15 #include "channels.h" 16 #include "users.h" 17 #include "logger.h" 18 #include "config.h" 19 #include "bots.h" 20 #include "servers.h" 21 #include "uplink.h" 22 #include "protocol.h" 23 24 #ifndef _WIN32 25 #include <sys/time.h> 26 #include <unistd.h> 27 #endif 28 29 static Anope::string GetTimeStamp() 30 { 31 char tbuf[256]; 32 time_t t; 33 34 if (time(&t) < 0) 35 t = Anope::CurTime; 36 37 tm tm = *localtime(&t); 38 if (Anope::Debug) 39 { 40 char *s; 41 struct timeval tv; 42 gettimeofday(&tv, NULL); 43 strftime(tbuf, sizeof(tbuf) - 1, "[%b %d %H:%M:%S", &tm); 44 s = tbuf + strlen(tbuf); 45 s += snprintf(s, sizeof(tbuf) - (s - tbuf), ".%06d", static_cast<int>(tv.tv_usec)); 46 strftime(s, sizeof(tbuf) - (s - tbuf) - 1, " %Y]", &tm); 47 } 48 else 49 strftime(tbuf, sizeof(tbuf) - 1, "[%b %d %H:%M:%S %Y]", &tm); 50 51 return tbuf; 52 } 53 54 static inline Anope::string CreateLogName(const Anope::string &file, time_t t = Anope::CurTime) 55 { 56 char timestamp[32]; 57 tm *tm = localtime(&t); 58 strftime(timestamp, sizeof(timestamp), "%Y%m%d", tm); 59 60 return Anope::LogDir + "/" + file + "." + timestamp; 61 } 62 63 LogFile::LogFile(const Anope::string &name) : filename(name), stream(name.c_str(), std::ios_base::out | std::ios_base::app) 64 { 65 } 66 67 LogFile::~LogFile() 68 { 69 this->stream.close(); 70 } 71 72 const Anope::string &LogFile::GetName() const 73 { 74 return this->filename; 75 } 76 77 Log::Log(LogType t, const Anope::string &cat, BotInfo *b) : bi(b), u(NULL), nc(NULL), c(NULL), source(NULL), chan(NULL), ci(NULL), s(NULL), m(NULL), type(t), category(cat) 78 { 79 } 80 81 Log::Log(LogType t, CommandSource &src, Command *_c, ChannelInfo *_ci) : u(src.GetUser()), nc(src.nc), c(_c), source(&src), chan(NULL), ci(_ci), s(NULL), m(NULL), type(t) 82 { 83 if (!c) 84 throw CoreException("Invalid pointers passed to Log::Log"); 85 86 if (type != LOG_COMMAND && type != LOG_OVERRIDE && type != LOG_ADMIN) 87 throw CoreException("This constructor does not support this log type"); 88 89 size_t sl = c->name.find('/'); 90 this->bi = NULL; 91 if (sl != Anope::string::npos) 92 this->bi = BotInfo::Find(c->name.substr(0, sl), true); 93 this->category = c->name; 94 } 95 96 Log::Log(User *_u, Channel *ch, const Anope::string &cat) : bi(NULL), u(_u), nc(NULL), c(NULL), source(NULL), chan(ch), ci(chan ? *chan->ci : NULL), s(NULL), m(NULL), type(LOG_CHANNEL), category(cat) 97 { 98 if (!chan) 99 throw CoreException("Invalid pointers passed to Log::Log"); 100 } 101 102 Log::Log(User *_u, const Anope::string &cat, BotInfo *_bi) : bi(_bi), u(_u), nc(NULL), c(NULL), source(NULL), chan(NULL), ci(NULL), s(NULL), m(NULL), type(LOG_USER), category(cat) 103 { 104 if (!u) 105 throw CoreException("Invalid pointers passed to Log::Log"); 106 } 107 108 Log::Log(Server *serv, const Anope::string &cat, BotInfo *_bi) : bi(_bi), u(NULL), nc(NULL), c(NULL), source(NULL), chan(NULL), ci(NULL), s(serv), m(NULL), type(LOG_SERVER), category(cat) 109 { 110 if (!s) 111 throw CoreException("Invalid pointer passed to Log::Log"); 112 } 113 114 Log::Log(BotInfo *b, const Anope::string &cat) : bi(b), u(NULL), nc(NULL), c(NULL), source(NULL), chan(NULL), ci(NULL), s(NULL), m(NULL), type(LOG_NORMAL), category(cat) 115 { 116 } 117 118 Log::Log(Module *mod, const Anope::string &cat, BotInfo *_bi) : bi(_bi), u(NULL), nc(NULL), c(NULL), source(NULL), chan(NULL), ci(NULL), s(NULL), m(mod), type(LOG_MODULE), category(cat) 119 { 120 } 121 122 Log::~Log() 123 { 124 if (Anope::NoFork && Anope::Debug && this->type >= LOG_NORMAL && this->type <= LOG_DEBUG + Anope::Debug - 1) 125 std::cout << GetTimeStamp() << " Debug: " << this->BuildPrefix() << this->buf.str() << std::endl; 126 else if (Anope::NoFork && this->type <= LOG_TERMINAL) 127 std::cout << GetTimeStamp() << " " << this->BuildPrefix() << this->buf.str() << std::endl; 128 else if (this->type == LOG_TERMINAL) 129 std::cout << this->BuildPrefix() << this->buf.str() << std::endl; 130 131 FOREACH_MOD(OnLog, (this)); 132 133 if (Config) 134 for (unsigned i = 0; i < Config->LogInfos.size(); ++i) 135 if (Config->LogInfos[i].HasType(this->type, this->category)) 136 Config->LogInfos[i].ProcessMessage(this); 137 } 138 139 Anope::string Log::FormatSource() const 140 { 141 if (u) 142 if (nc) 143 return this->u->GetMask() + " (" + this->nc->display + ")"; 144 else 145 return this->u->GetMask(); 146 else if (nc) 147 return nc->display; 148 else if (source) 149 { 150 Anope::string nickbuf = source->GetNick(); 151 if (!nickbuf.empty() && !source->ip.empty()) 152 nickbuf += " (" + source->ip + ")"; 153 return nickbuf; 154 } 155 return ""; 156 } 157 158 Anope::string Log::FormatCommand() const 159 { 160 Anope::string buffer = FormatSource() + " used " + (source != NULL && !source->command.empty() ? source->command : this->c->name) + " "; 161 if (this->ci) 162 buffer += "on " + this->ci->name + " "; 163 164 return buffer; 165 } 166 167 Anope::string Log::BuildPrefix() const 168 { 169 Anope::string buffer; 170 171 switch (this->type) 172 { 173 case LOG_ADMIN: 174 { 175 if (!this->c) 176 break; 177 buffer += "ADMIN: " + FormatCommand(); 178 break; 179 } 180 case LOG_OVERRIDE: 181 { 182 if (!this->c) 183 break; 184 buffer += "OVERRIDE: " + FormatCommand(); 185 break; 186 } 187 case LOG_COMMAND: 188 { 189 if (!this->c) 190 break; 191 buffer += "COMMAND: " + FormatCommand(); 192 break; 193 } 194 case LOG_CHANNEL: 195 { 196 if (!this->chan) 197 break; 198 buffer += "CHANNEL: "; 199 Anope::string src = FormatSource(); 200 if (!src.empty()) 201 buffer += src + " "; 202 buffer += this->category + " " + this->chan->name + " "; 203 break; 204 } 205 case LOG_USER: 206 { 207 if (this->u) 208 buffer += "USERS: " + FormatSource() + " "; 209 break; 210 } 211 case LOG_SERVER: 212 { 213 if (this->s) 214 buffer += "SERVER: " + this->s->GetName() + " (" + this->s->GetDescription() + ") "; 215 break; 216 } 217 case LOG_MODULE: 218 { 219 if (this->m) 220 buffer += this->m->name.upper() + ": "; 221 break; 222 } 223 default: 224 break; 225 } 226 227 return buffer; 228 } 229 230 LogInfo::LogInfo(int la, bool rio, bool ldebug) : bot(NULL), last_day(0), log_age(la), raw_io(rio), debug(ldebug) 231 { 232 } 233 234 LogInfo::~LogInfo() 235 { 236 for (unsigned i = 0; i < this->logfiles.size(); ++i) 237 delete this->logfiles[i]; 238 this->logfiles.clear(); 239 } 240 241 bool LogInfo::HasType(LogType ltype, const Anope::string &type) const 242 { 243 const std::vector<Anope::string> *list = NULL; 244 switch (ltype) 245 { 246 case LOG_ADMIN: 247 list = &this->admin; 248 break; 249 case LOG_OVERRIDE: 250 list = &this->override; 251 break; 252 case LOG_COMMAND: 253 list = &this->commands; 254 break; 255 case LOG_SERVER: 256 list = &this->servers; 257 break; 258 case LOG_CHANNEL: 259 list = &this->channels; 260 break; 261 case LOG_USER: 262 list = &this->users; 263 break; 264 case LOG_TERMINAL: 265 return true; 266 case LOG_RAWIO: 267 return (Anope::Debug || this->debug) ? true : this->raw_io; 268 case LOG_DEBUG: 269 return Anope::Debug ? true : this->debug; 270 case LOG_DEBUG_2: 271 case LOG_DEBUG_3: 272 case LOG_DEBUG_4: 273 break; 274 case LOG_MODULE: 275 case LOG_NORMAL: 276 default: 277 list = &this->normal; 278 break; 279 } 280 281 if (list == NULL) 282 return false; 283 284 for (unsigned i = 0; i < list->size(); ++i) 285 { 286 Anope::string cat = list->at(i); 287 bool inverse = false; 288 if (cat[0] == '~') 289 { 290 cat.erase(cat.begin()); 291 inverse = true; 292 } 293 if (Anope::Match(type, cat)) 294 { 295 return !inverse; 296 } 297 } 298 299 return false; 300 } 301 302 void LogInfo::OpenLogFiles() 303 { 304 for (unsigned i = 0; i < this->logfiles.size(); ++i) 305 delete this->logfiles[i]; 306 this->logfiles.clear(); 307 308 for (unsigned i = 0; i < this->targets.size(); ++i) 309 { 310 const Anope::string &target = this->targets[i]; 311 312 if (target.empty() || target[0] == '#' || target == "globops" || target.find(":") != Anope::string::npos) 313 continue; 314 315 LogFile *lf = new LogFile(CreateLogName(target)); 316 if (!lf->stream.is_open()) 317 { 318 Log() << "Unable to open logfile " << lf->GetName(); 319 delete lf; 320 } 321 else 322 this->logfiles.push_back(lf); 323 } 324 } 325 326 void LogInfo::ProcessMessage(const Log *l) 327 { 328 if (!this->sources.empty()) 329 { 330 bool log = false; 331 for (unsigned i = 0; i < this->sources.size() && !log; ++i) 332 { 333 const Anope::string &src = this->sources[i]; 334 335 if (l->bi && src == l->bi->nick) 336 log = true; 337 else if (l->u && src == l->u->nick) 338 log = true; 339 else if (l->nc && src == l->nc->display) 340 log = true; 341 else if (l->ci && src == l->ci->name) 342 log = true; 343 else if (l->m && src == l->m->name) 344 log = true; 345 else if (l->s && src == l->s->GetName()) 346 log = true; 347 } 348 if (!log) 349 return; 350 } 351 352 const Anope::string &buffer = l->BuildPrefix() + l->buf.str(); 353 354 FOREACH_MOD(OnLogMessage, (this, l, buffer)); 355 356 for (unsigned i = 0; i < this->targets.size(); ++i) 357 { 358 const Anope::string &target = this->targets[i]; 359 360 if (!target.empty() && target[0] == '#') 361 { 362 if (UplinkSock && l->type <= LOG_NORMAL && Me && Me->IsSynced()) 363 { 364 Channel *c = Channel::Find(target); 365 if (!c) 366 continue; 367 368 BotInfo *bi = l->bi; 369 if (!bi) 370 bi = this->bot; 371 if (!bi) 372 bi = c->ci->WhoSends(); 373 if (bi) 374 IRCD->SendPrivmsg(bi, c->name, "%s", buffer.c_str()); 375 } 376 } 377 else if (target == "globops") 378 { 379 if (UplinkSock && l->type <= LOG_NORMAL && Me && Me->IsSynced()) 380 { 381 BotInfo *bi = l->bi; 382 if (!bi) 383 bi = this->bot; 384 if (bi) 385 IRCD->SendGlobops(bi, "%s", buffer.c_str()); 386 } 387 } 388 } 389 390 tm *tm = localtime(&Anope::CurTime); 391 if (tm->tm_mday != this->last_day) 392 { 393 this->last_day = tm->tm_mday; 394 this->OpenLogFiles(); 395 396 if (this->log_age) 397 for (unsigned i = 0; i < this->targets.size(); ++i) 398 { 399 const Anope::string &target = this->targets[i]; 400 401 if (target.empty() || target[0] == '#' || target == "globops" || target.find(":") != Anope::string::npos) 402 continue; 403 404 Anope::string oldlog = CreateLogName(target, Anope::CurTime - 86400 * this->log_age); 405 if (IsFile(oldlog)) 406 { 407 unlink(oldlog.c_str()); 408 Log(LOG_DEBUG) << "Deleted old logfile " << oldlog; 409 } 410 } 411 } 412 413 for (unsigned i = 0; i < this->logfiles.size(); ++i) 414 { 415 LogFile *lf = this->logfiles[i]; 416 lf->stream << GetTimeStamp() << " " << buffer << std::endl; 417 } 418 }