00001
00002
00003
00004
00005
00006
00007
00008
00009
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
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
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
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> ¶ms) 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)