diff options
author | Adam <Adam@anope.org> | 2012-10-02 05:18:42 -0400 |
---|---|---|
committer | Adam <Adam@anope.org> | 2012-10-02 05:18:42 -0400 |
commit | 93698f0d61935f86019b3491c9e62c6326a180ba (patch) | |
tree | 60d1cee36e8f2772aaaeb8ddde19a97ee3d55c94 /modules/commands/os_logsearch.cpp | |
parent | f7aa8376969824bcfeb39044e8a1e89cd58b4b02 (diff) |
Added operserv/logsearch
Diffstat (limited to 'modules/commands/os_logsearch.cpp')
-rw-r--r-- | modules/commands/os_logsearch.cpp | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/modules/commands/os_logsearch.cpp b/modules/commands/os_logsearch.cpp new file mode 100644 index 000000000..806d35ca1 --- /dev/null +++ b/modules/commands/os_logsearch.cpp @@ -0,0 +1,169 @@ +/* OperServ core functions + * + * (C) 2003-2012 Anope Team + * Contact us at team@anope.org + * + * Please read COPYING and README for further details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + */ + +#include "module.h" + +static Anope::string logfile_name; + +class CommandOSLogSearch : public Command +{ + static inline Anope::string CreateLogName(const Anope::string &file, time_t t = Anope::CurTime) + { + char timestamp[32]; + + tm *tm = localtime(&t); + + strftime(timestamp, sizeof(timestamp), "%Y%m%d", tm); + + return log_dir + "/" + file + "." + timestamp; + } + + public: + CommandOSLogSearch(Module *creator) : Command(creator, "operserv/logsearch", 1, 3) + { + this->SetDesc(_("Searches logs for a matching pattern")); + this->SetSyntax(_("[+\037days\037d] [+\037limit\037l] \037pattern\037")); + } + + void Execute(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override + { + int days = 7, replies = 50; + + unsigned i; + for (i = 0; i < params.size() && params[i][0] == '+'; ++i) + { + switch (params[i][params[i].length() - 1]) + { + case 'd': + if (params[i].length() > 2) + { + Anope::string dur = params[i].substr(1, params[i].length() - 2); + try + { + days = convertTo<int>(dur); + if (days <= 0) + throw ConvertException(); + } + catch (const ConvertException &) + { + source.Reply(_("Invalid duration %s, using %d days"), dur.c_str(), days); + } + } + break; + case 'l': + if (params[i].length() > 2) + { + Anope::string dur = params[i].substr(1, params[i].length() - 2); + try + { + replies = convertTo<int>(dur); + if (replies <= 0) + throw ConvertException(); + } + catch (const ConvertException &) + { + source.Reply(_("Invalid limit %s, using %d"), dur.c_str(), replies); + } + } + break; + default: + source.Reply(_("Unknown parameter %s"), params[i].c_str()); + } + } + + if (i >= params.size()) + { + this->OnSyntaxError(source, ""); + return; + } + + Anope::string search_string = params[i++]; + for (; i < params.size(); ++i) + search_string += " " + params[i]; + + Log(LOG_ADMIN, source, this) << "for " << search_string; + + std::list<Anope::string> matches; + for (int d = 0; d < days; ++d) + { + Anope::string lf_name = CreateLogName(logfile_name, Anope::CurTime - (d * 86400)); + Log(LOG_DEBUG) << "Searching " << lf_name; + std::fstream fd(lf_name.c_str(), std::ios_base::in); + if (!fd.is_open()) + continue; + + for (Anope::string buf, token; std::getline(fd, buf.str());) + if (Anope::Match(buf, "*" + search_string + "*")) + matches.push_back(buf); + + fd.close(); + } + + unsigned found = matches.size(); + if (!found) + { + source.Reply(_("No matches for \2%s\2 found."), search_string.c_str()); + return; + } + + while (matches.size() > static_cast<unsigned>(replies)) + matches.pop_front(); + + source.Reply(_("Matches for \2%s\2:"), search_string.c_str()); + unsigned count = 0; + for (std::list<Anope::string>::iterator it = matches.begin(), it_end = matches.end(); it != it_end; ++it) + source.Reply("#%d: %s", ++count, it->c_str()); + source.Reply(_("Showed %d/%d matches for \2%s\2"), replies, found, search_string.c_str()); + } + + bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override + { + this->SendSyntax(source); + source.Reply(" "); + source.Reply(_("This command searches the Services logfiles for messages\n" + "that match the given pattern. The day and limit argument\n" + "may be used to specifcy how many days of logs to search\n" + "and the number of replies to limit to. By default this\n" + "command searches one week of logs, and limits replies\n" + "to 50.\n" + "\n" + "For example:\n" + " \2LOGSEARCH 21d 500l Anope\2\n" + " Searches the last 21 days worth of logs for messages\n" + " containing Anope and lists the most recent 500 of them.\n")); + return true; + } +}; + +class OSLogSearch : public Module +{ + CommandOSLogSearch commandoslogsearch; + + public: + OSLogSearch(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), + commandoslogsearch(this) + { + this->SetAuthor("Anope"); + + Implementation i[] = { I_OnReload }; + ModuleManager::Attach(i, this, sizeof(i) / sizeof(Implementation)); + + OnReload(); + } + + void OnReload() anope_override + { + ConfigReader config; + logfile_name = config.ReadValue("logsearch", "name", "services.log", 0); + } +}; + +MODULE_INIT(OSLogSearch) |