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