anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

os_stats.cpp (9510B)

      1 /* OperServ core functions
      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 "module.h"
     13 #include "modules/os_session.h"
     14 
     15 struct Stats : Serializable
     16 {
     17 	static Stats *me;
     18 
     19 	Stats() : Serializable("Stats")
     20 	{
     21 		me = this;
     22 	}
     23 
     24 	void Serialize(Serialize::Data &data) const anope_override
     25 	{
     26 		data["maxusercnt"] << MaxUserCount;
     27 		data["maxusertime"] << MaxUserTime;
     28 	}
     29 
     30 	static Serializable* Unserialize(Serializable *obj, Serialize::Data &data)
     31 	{
     32 		data["maxusercnt"] >> MaxUserCount;
     33 		data["maxusertime"] >> MaxUserTime;
     34 		return me;
     35 	}
     36 };
     37 
     38 Stats *Stats::me;
     39 
     40 /**
     41  * Count servers connected to server s
     42  * @param s The server to start counting from
     43  * @return Amount of servers connected to server s
     44  **/
     45 static int stats_count_servers(Server *s)
     46 {
     47 	if (!s)
     48 		return 0;
     49 
     50 	int count = 1;
     51 
     52 	if (!s->GetLinks().empty())
     53 		for (unsigned i = 0, j = s->GetLinks().size(); i < j; ++i)
     54 			count += stats_count_servers(s->GetLinks()[i]);
     55 
     56 	return count;
     57 }
     58 
     59 class CommandOSStats : public Command
     60 {
     61 	ServiceReference<XLineManager> akills, snlines, sqlines;
     62  private:
     63 	void DoStatsAkill(CommandSource &source)
     64 	{
     65 		int timeout;
     66 		if (akills)
     67 		{
     68 			/* AKILLs */
     69 			source.Reply(_("Current number of AKILLs: \002%d\002"), akills->GetCount());
     70 			timeout = Config->GetModule("operserv")->Get<time_t>("autokillexpiry", "30d") + 59;
     71 			if (timeout >= 172800)
     72 				source.Reply(_("Default AKILL expiry time: \002%d days\002"), timeout / 86400);
     73 			else if (timeout >= 86400)
     74 				source.Reply(_("Default AKILL expiry time: \0021 day\002"));
     75 			else if (timeout >= 7200)
     76 				source.Reply(_("Default AKILL expiry time: \002%d hours\002"), timeout / 3600);
     77 			else if (timeout >= 3600)
     78 				source.Reply(_("Default AKILL expiry time: \0021 hour\002"));
     79 			else if (timeout >= 120)
     80 				source.Reply(_("Default AKILL expiry time: \002%d minutes\002"), timeout / 60);
     81 			else if (timeout >= 60)
     82 				source.Reply(_("Default AKILL expiry time: \0021 minute\002"));
     83 			else
     84 				source.Reply(_("Default AKILL expiry time: \002No expiration\002"));
     85 		}
     86 		if (snlines)
     87 		{
     88 			/* SNLINEs */
     89 			source.Reply(_("Current number of SNLINEs: \002%d\002"), snlines->GetCount());
     90 			timeout = Config->GetModule("operserv")->Get<time_t>("snlineexpiry", "30d") + 59;
     91 			if (timeout >= 172800)
     92 				source.Reply(_("Default SNLINE expiry time: \002%d days\002"), timeout / 86400);
     93 			else if (timeout >= 86400)
     94 				source.Reply(_("Default SNLINE expiry time: \0021 day\002"));
     95 			else if (timeout >= 7200)
     96 				source.Reply(_("Default SNLINE expiry time: \002%d hours\002"), timeout / 3600);
     97 			else if (timeout >= 3600)
     98 				source.Reply(_("Default SNLINE expiry time: \0021 hour\002"));
     99 			else if (timeout >= 120)
    100 				source.Reply(_("Default SNLINE expiry time: \002%d minutes\002"), timeout / 60);
    101 			else if (timeout >= 60)
    102 				source.Reply(_("Default SNLINE expiry time: \0021 minute\002"));
    103 			else
    104 				source.Reply(_("Default SNLINE expiry time: \002No expiration\002"));
    105 		}
    106 		if (sqlines)
    107 		{
    108 			/* SQLINEs */
    109 			source.Reply(_("Current number of SQLINEs: \002%d\002"), sqlines->GetCount());
    110 			timeout = Config->GetModule("operserv")->Get<time_t>("sglineexpiry", "30d") + 59;
    111 			if (timeout >= 172800)
    112 				source.Reply(_("Default SQLINE expiry time: \002%d days\002"), timeout / 86400);
    113 			else if (timeout >= 86400)
    114 				source.Reply(_("Default SQLINE expiry time: \0021 day\002"));
    115 			else if (timeout >= 7200)
    116 				source.Reply(_("Default SQLINE expiry time: \002%d hours\002"), timeout / 3600);
    117 			else if (timeout >= 3600)
    118 				source.Reply(_("Default SQLINE expiry time: \0021 hour\002"));
    119 			else if (timeout >= 120)
    120 				source.Reply(_("Default SQLINE expiry time: \002%d minutes\002"), timeout / 60);
    121 			else if (timeout >= 60)
    122 				source.Reply(_("Default SQLINE expiry time: \0021 minute\002"));
    123 			else
    124 				source.Reply(_("Default SQLINE expiry time: \002No expiration\002"));
    125 		}
    126 	}
    127 
    128 	void DoStatsReset(CommandSource &source)
    129 	{
    130 		MaxUserCount = UserListByNick.size();
    131 		source.Reply(_("Statistics reset."));
    132 		return;
    133 	}
    134 
    135 	void DoStatsUptime(CommandSource &source)
    136 	{
    137 		time_t uptime = Anope::CurTime - Anope::StartTime;
    138 		source.Reply(_("Current users: \002%d\002 (\002%d\002 ops)"), UserListByNick.size(), OperCount);
    139 		source.Reply(_("Maximum users: \002%d\002 (%s)"), MaxUserCount, Anope::strftime(MaxUserTime, source.GetAccount()).c_str());
    140 		source.Reply(_("Services up %s."), Anope::Duration(uptime, source.GetAccount()).c_str());
    141 
    142 		return;
    143 	}
    144 
    145 	void DoStatsUplink(CommandSource &source)
    146 	{
    147 		Anope::string buf;
    148 		for (std::set<Anope::string>::iterator it = Servers::Capab.begin(); it != Servers::Capab.end(); ++it)
    149 			buf += " " + *it;
    150 		if (!buf.empty())
    151 			buf.erase(buf.begin());
    152 
    153 		source.Reply(_("Uplink server: %s"), Me->GetLinks().front()->GetName().c_str());
    154 		source.Reply(_("Uplink capab: %s"), buf.c_str());
    155 		source.Reply(_("Servers found: %d"), stats_count_servers(Me->GetLinks().front()));
    156 		return;
    157 	}
    158 
    159 	template<typename T> void GetHashStats(const T& map, size_t& entries, size_t& buckets, size_t& max_chain)
    160 	{
    161 		entries = map.size(), buckets = map.bucket_count(), max_chain = 0;
    162 		for (size_t i = 0; i < buckets; ++i)
    163 			if (map.bucket_size(i) > max_chain)
    164 				max_chain = map.bucket_size(i);
    165 	}
    166 
    167 	void DoStatsHash(CommandSource &source)
    168 	{
    169 		size_t entries, buckets, max_chain;
    170 
    171 		GetHashStats(UserListByNick, entries, buckets, max_chain);
    172 		source.Reply(_("Users (nick): %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
    173 
    174 		if (!UserListByUID.empty())
    175 		{
    176 			GetHashStats(UserListByUID, entries, buckets, max_chain);
    177 			source.Reply(_("Users (uid): %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
    178 		}
    179 
    180 		GetHashStats(ChannelList, entries, buckets, max_chain);
    181 		source.Reply(_("Channels: %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
    182 
    183 		GetHashStats(*RegisteredChannelList, entries, buckets, max_chain);
    184 		source.Reply(_("Registered channels: %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
    185 
    186 		GetHashStats(*NickAliasList, entries, buckets, max_chain);
    187 		source.Reply(_("Registered nicknames: %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
    188 
    189 		GetHashStats(*NickCoreList, entries, buckets, max_chain);
    190 		source.Reply(_("Registered nick groups: %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
    191 
    192 		if (session_service)
    193 		{
    194 			GetHashStats(session_service->GetSessions(), entries, buckets, max_chain);
    195 			source.Reply(_("Sessions: %lu entries, %lu buckets, longest chain is %d"), entries, buckets, max_chain);
    196 		}
    197 	}
    198 
    199  public:
    200 	CommandOSStats(Module *creator) : Command(creator, "operserv/stats", 0, 1),
    201 		akills("XLineManager", "xlinemanager/sgline"), snlines("XLineManager", "xlinemanager/snline"), sqlines("XLineManager", "xlinemanager/sqline")
    202 	{
    203 		this->SetDesc(_("Show status of Services and network"));
    204 		this->SetSyntax("[AKILL | HASH | UPLINK | UPTIME | ALL | RESET]");
    205 	}
    206 
    207 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
    208 	{
    209 		Anope::string extra = !params.empty() ? params[0] : "";
    210 
    211 		Log(LOG_ADMIN, source, this) << extra;
    212 
    213 		if (extra.equals_ci("RESET"))
    214 			return this->DoStatsReset(source);
    215 
    216 		if (extra.equals_ci("ALL") || extra.equals_ci("AKILL"))
    217 			this->DoStatsAkill(source);
    218 
    219 		if (extra.equals_ci("ALL") || extra.equals_ci("HASH"))
    220 			this->DoStatsHash(source);
    221 
    222 		if (extra.equals_ci("ALL") || extra.equals_ci("UPLINK"))
    223 			this->DoStatsUplink(source);
    224 
    225 		if (extra.empty() || extra.equals_ci("ALL") || extra.equals_ci("UPTIME"))
    226 			this->DoStatsUptime(source);
    227 
    228 		if (!extra.empty() && !extra.equals_ci("ALL") && !extra.equals_ci("AKILL") && !extra.equals_ci("HASH") && !extra.equals_ci("UPLINK") && !extra.equals_ci("UPTIME"))
    229 			source.Reply(_("Unknown STATS option: \002%s\002"), extra.c_str());
    230 	}
    231 
    232 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
    233 	{
    234 		this->SendSyntax(source);
    235 		source.Reply(" ");
    236 		source.Reply(_("Without any option, shows the current number of users online,\n"
    237 				"and the highest number of users online since Services was\n"
    238 				"started, and the length of time Services has been running.\n"
    239 				" \n"
    240 				"With the \002AKILL\002 option, displays the current size of the\n"
    241 				"AKILL list and the current default expiry time.\n"
    242 				" \n"
    243 				"The \002RESET\002 option currently resets the maximum user count\n"
    244 				"to the number of users currently present on the network.\n"
    245 				" \n"
    246 				"The \002UPLINK\002 option displays information about the current\n"
    247 				"server Anope uses as an uplink to the network.\n"
    248 				" \n"
    249 				"The \002HASH\002 option displays information about the hash maps.\n"
    250 				" \n"
    251 				"The \002ALL\002 option displays all of the above statistics."));
    252 		return true;
    253 	}
    254 };
    255 
    256 class OSStats : public Module
    257 {
    258 	CommandOSStats commandosstats;
    259 	Serialize::Type stats_type;
    260 	Stats stats_saver;
    261 
    262  public:
    263 	OSStats(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
    264 		commandosstats(this), stats_type("Stats", Stats::Unserialize)
    265 	{
    266 
    267 	}
    268 
    269 	void OnUserConnect(User *u, bool &exempt) anope_override
    270 	{
    271 		if (UserListByNick.size() == MaxUserCount && Anope::CurTime == MaxUserTime)
    272 			stats_saver.QueueUpdate();
    273 	}
    274 };
    275 
    276 MODULE_INIT(OSStats)