os_stats.cpp

Go to the documentation of this file.
00001 /* OperServ core functions
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 /*************************************************************************/
00013 
00014 #include "module.h"
00015 #include "os_session.h"
00016 
00017 struct Stats : Serializable
00018 {
00019         Stats() : Serializable("Stats") { }
00020 
00021         void Serialize(Serialize::Data &data) const anope_override
00022         {
00023                 data["maxusercnt"] << MaxUserCount;
00024                 data["maxusertime"] << MaxUserTime;
00025         }
00026 
00027         static Serializable* Unserialize(Serializable *obj, Serialize::Data &data)
00028         {
00029                 data["maxusercnt"] >> MaxUserCount;
00030                 data["maxusertime"] >> MaxUserTime;
00031                 return NULL;
00032         }
00033 };
00034 
00040 static int stats_count_servers(Server *s)
00041 {
00042         if (!s)
00043                 return 0;
00044 
00045         int count = 1;
00046 
00047         if (!s->GetLinks().empty())
00048                 for (unsigned i = 0, j = s->GetLinks().size(); i < j; ++i)
00049                         count += stats_count_servers(s->GetLinks()[i]);
00050 
00051         return count;
00052 }
00053 
00054 class CommandOSStats : public Command
00055 {
00056         ServiceReference<XLineManager> akills, snlines, sqlines;
00057  private:
00058         void DoStatsAkill(CommandSource &source)
00059         {
00060                 int timeout;
00061                 if (akills)
00062                 {
00063                         /* AKILLs */
00064                         source.Reply(_("Current number of AKILLs: \002%d\002"), akills->GetCount());
00065                         timeout = Config->AutokillExpiry + 59;
00066                         if (timeout >= 172800)
00067                                 source.Reply(_("Default AKILL expiry time: \002%d days\002"), timeout / 86400);
00068                         else if (timeout >= 86400)
00069                                 source.Reply(_("Default AKILL expiry time: \0021 day\002"));
00070                         else if (timeout >= 7200)
00071                                 source.Reply(_("Default AKILL expiry time: \002%d hours\002"), timeout / 3600);
00072                         else if (timeout >= 3600)
00073                                 source.Reply(_("Default AKILL expiry time: \0021 hour\002"));
00074                         else if (timeout >= 120)
00075                                 source.Reply(_("Default AKILL expiry time: \002%d minutes\002"), timeout / 60);
00076                         else if (timeout >= 60)
00077                                 source.Reply(_("Default AKILL expiry time: \0021 minute\002"));
00078                         else
00079                                 source.Reply(_("Default AKILL expiry time: \002No expiration\002"));
00080                 }
00081                 if (IRCD->CanSNLine && snlines)
00082                 {
00083                         /* SNLINEs */
00084                         source.Reply(_("Current number of SNLINEs: \002%d\002"), snlines->GetCount());
00085                         timeout = Config->SNLineExpiry + 59;
00086                         if (timeout >= 172800)
00087                                 source.Reply(_("Default SNLINE expiry time: \002%d days\002"), timeout / 86400);
00088                         else if (timeout >= 86400)
00089                                 source.Reply(_("Default SNLINE expiry time: \0021 day\002"));
00090                         else if (timeout >= 7200)
00091                                 source.Reply(_("Default SNLINE expiry time: \002%d hours\002"), timeout / 3600);
00092                         else if (timeout >= 3600)
00093                                 source.Reply(_("Default SNLINE expiry time: \0021 hour\002"));
00094                         else if (timeout >= 120)
00095                                 source.Reply(_("Default SNLINE expiry time: \002%d minutes\002"), timeout / 60);
00096                         else if (timeout >= 60)
00097                                 source.Reply(_("Default SNLINE expiry time: \0021 minute\002"));
00098                         else
00099                                 source.Reply(_("Default SNLINE expiry time: \002No expiration\002"));
00100                 }
00101                 if (IRCD->CanSQLine && sqlines)
00102                 {
00103                         /* SQLINEs */
00104                         source.Reply(_("Current number of SQLINEs: \002%d\002"), sqlines->GetCount());
00105                         timeout = Config->SQLineExpiry + 59;
00106                         if (timeout >= 172800)
00107                                 source.Reply(_("Default SQLINE expiry time: \002%d days\002"), timeout / 86400);
00108                         else if (timeout >= 86400)
00109                                 source.Reply(_("Default SQLINE expiry time: \0021 day\002"));
00110                         else if (timeout >= 7200)
00111                                 source.Reply(_("Default SQLINE expiry time: \002%d hours\002"), timeout / 3600);
00112                         else if (timeout >= 3600)
00113                                 source.Reply(_("Default SQLINE expiry time: \0021 hour\002"));
00114                         else if (timeout >= 120)
00115                                 source.Reply(_("Default SQLINE expiry time: \002%d minutes\002"), timeout / 60);
00116                         else if (timeout >= 60)
00117                                 source.Reply(_("Default SQLINE expiry time: \0021 minute\002"));
00118                         else
00119                                 source.Reply(_("Default SQLINE expiry time: \002No expiration\002"));
00120                 }
00121                 return;
00122         }
00123 
00124         void DoStatsReset(CommandSource &source)
00125         {
00126                 MaxUserCount = UserListByNick.size();
00127                 source.Reply(_("Statistics reset."));
00128                 return;
00129         }
00130 
00131         void DoStatsUptime(CommandSource &source)
00132         {
00133                 time_t uptime = Anope::CurTime - Anope::StartTime;
00134                 source.Reply(_("Current users: \002%d\002 (\002%d\002 ops)"), UserListByNick.size(), OperCount);
00135                 source.Reply(_("Maximum users: \002%d\002 (%s)"), MaxUserCount, Anope::strftime(MaxUserTime).c_str());
00136                 source.Reply(_("Services up %s."), Anope::Duration(uptime).c_str());
00137 
00138                 return;
00139         }
00140 
00141         void DoStatsUplink(CommandSource &source)
00142         {
00143                 Anope::string buf;
00144                 for (std::set<Anope::string>::iterator it = Servers::Capab.begin(); it != Servers::Capab.end(); ++it)
00145                         buf += " " + *it;
00146                 if (!buf.empty())
00147                         buf.erase(buf.begin());
00148 
00149                 source.Reply(_("Uplink server: %s"), Me->GetLinks().front()->GetName().c_str());
00150                 source.Reply(_("Uplink capab: %s"), buf.c_str());
00151                 source.Reply(_("Servers found: %d"), stats_count_servers(Me->GetLinks().front()));
00152                 return;
00153         }
00154 
00155         template<typename T> void GetHashStats(const T& map, size_t& entries, size_t& buckets, size_t& max_chain)
00156         {
00157                 entries = map.size(), buckets = map.bucket_count(), max_chain = 0;
00158                 for (size_t i = 0; i < buckets; ++i)
00159                         if (map.bucket_size(i) > max_chain)
00160                                 max_chain = map.bucket_size(i);
00161         }
00162 
00163         void DoStatsHash(CommandSource &source)
00164         {
00165                 size_t entries, buckets, max_chain;
00166 
00167                 GetHashStats(UserListByNick, entries, buckets, max_chain);
00168                 source.Reply(_("Users (nick): %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
00169 
00170                 if (!UserListByUID.empty())
00171                 {
00172                         GetHashStats(UserListByUID, entries, buckets, max_chain);
00173                         source.Reply(_("Users (uid): %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
00174                 }
00175 
00176                 GetHashStats(ChannelList, entries, buckets, max_chain);
00177                 source.Reply(_("Channels: %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
00178 
00179                 GetHashStats(*RegisteredChannelList, entries, buckets, max_chain);
00180                 source.Reply(_("Registered channels: %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
00181 
00182                 GetHashStats(*NickAliasList, entries, buckets, max_chain);
00183                 source.Reply(_("Registered nicknames: %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
00184 
00185                 GetHashStats(*NickCoreList, entries, buckets, max_chain);
00186                 source.Reply(_("Registered nick groups: %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
00187 
00188                 if (session_service)
00189                 {
00190                         GetHashStats(session_service->GetSessions(), entries, buckets, max_chain);
00191                         source.Reply(_("Sessions: %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
00192                 }
00193         }
00194 
00195  public:
00196         CommandOSStats(Module *creator) : Command(creator, "operserv/stats", 0, 1),
00197                 akills("XLineManager", "xlinemanager/sgline"), snlines("XLineManager", "xlinemanager/snline"), sqlines("XLineManager", "xlinemanager/sqline")
00198         {
00199                 this->SetDesc(_("Show status of Services and network"));
00200                 this->SetSyntax(_("[AKILL | HASH | UPLINK | UPTIME | ALL | RESET]"));
00201         }
00202 
00203         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00204         {
00205                 Anope::string extra = !params.empty() ? params[0] : "";
00206 
00207                 if (extra.equals_ci("RESET"))
00208                         return this->DoStatsReset(source);
00209 
00210                 if (extra.equals_ci("ALL") || extra.equals_ci("AKILL"))
00211                         this->DoStatsAkill(source);
00212 
00213                 if (extra.equals_ci("ALL") || extra.equals_ci("HASH"))
00214                         this->DoStatsHash(source);
00215 
00216                 if (extra.equals_ci("ALL") || extra.equals_ci("UPLINK"))
00217                         this->DoStatsUplink(source);
00218 
00219                 if (extra.empty() || extra.equals_ci("ALL") || extra.equals_ci("UPTIME"))
00220                         this->DoStatsUptime(source);
00221 
00222                 if (!extra.empty() && !extra.equals_ci("ALL") && !extra.equals_ci("AKILL") && !extra.equals_ci("HASH") && !extra.equals_ci("UPLINK") && !extra.equals_ci("UPTIME"))
00223                         source.Reply(_("Unknown STATS option: \002%s\002"), extra.c_str());
00224         }
00225 
00226         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00227         {
00228                 this->SendSyntax(source);
00229                 source.Reply(" ");
00230                 source.Reply(_("Without any option, shows the current number of users online,\n"
00231                                 "and the highest number of users online since Services was\n"
00232                                 "started, and the length of time Services has been running.\n"
00233                                 " \n"
00234                                 "With the \002AKILL\002 option, displays the current size of the\n"
00235                                 "AKILL list and the current default expiry time.\n"
00236                                 " \n"
00237                                 "The \002RESET\002 option currently resets the maximum user count\n"
00238                                 "to the number of users currently present on the network.\n"
00239                                 " \n"
00240                                 "The \002UPLINK\002 option displays information about the current\n"
00241                                 "server Anope uses as an uplink to the network.\n"
00242                                 " \n"
00243                                 "The \002HASH\002 option displays information about the hash maps.\n"
00244                                 " \n"
00245                                 "The \002ALL\002 displays the user and uptime statistics, and\n"
00246                                 "everything you'd see with the \002UPLINK\002 option."));
00247                 return true;
00248         }
00249 };
00250 
00251 class OSStats : public Module
00252 {
00253         CommandOSStats commandosstats;
00254         Serialize::Type stats_type;
00255         Stats stats_saver;
00256 
00257  public:
00258         OSStats(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE),
00259                 commandosstats(this), stats_type("Stats", Stats::Unserialize)
00260         {
00261                 this->SetAuthor("Anope");
00262 
00263         }
00264 };
00265 
00266 MODULE_INIT(OSStats)