From bbd393d84f2782cdbbafe912619572fcc21a8251 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 25 Oct 2014 22:35:26 +0200 Subject: [PATCH] log: add support for logging rules By default, everything is logged. The first matching rule wins. Negation (!) and wildcards (*) are supported. For example, disable logging for all channels, except #znc: /msg *log setrules #znc !#* Queries do not match either of the above rules, so they get logged. --- modules/log.cpp | 139 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/modules/log.cpp b/modules/log.cpp index 24155944..e6b3055a 100644 --- a/modules/log.cpp +++ b/modules/log.cpp @@ -20,16 +20,57 @@ #include #include #include +#include using std::vector; +class CLogRule { +public: + CLogRule(const CString& sRule, bool bEnabled = true) : m_sRule(sRule), m_bEnabled(bEnabled) {} + + const CString& GetRule() const { return m_sRule; } + bool IsEnabled() const { return m_bEnabled; } + void SetEnabled(bool bEnabled) { m_bEnabled = bEnabled; } + + bool Compare(const CString& sTarget) const { + return sTarget.WildCmp(m_sRule); + } + + bool operator==(const CLogRule& sOther) const { + return m_sRule == sOther.GetRule(); + } + + CString ToString() const { + return (m_bEnabled ? "" : "!") + m_sRule; + } + +private: + CString m_sRule; + bool m_bEnabled; +}; + class CLogMod: public CModule { public: MODCONSTRUCTOR(CLogMod) { m_bSanitize = false; + AddHelpCommand(); + AddCommand("SetRules", static_cast(&CLogMod::SetRulesCmd), + "", "Set logging rules, use !#chan or !query to negate and * for wildcards"); + AddCommand("ClearRules", static_cast(&CLogMod::ClearRulesCmd), + "", "Clear all logging rules"); + AddCommand("ListRules", static_cast(&CLogMod::ListRulesCmd), + "", "List all logging rules"); } + void SetRulesCmd(const CString& sLine); + void ClearRulesCmd(const CString& sLine); + void ListRulesCmd(const CString& sLine = ""); + void SetRules(const VCString& vsRules); + VCString SplitRules(const CString& sRules) const; + CString JoinRules(const CString& sSeparator) const; + bool TestRules(const CString& sTarget) const; + void PutLog(const CString& sLine, const CString& sWindow = "status"); void PutLog(const CString& sLine, const CChan& Channel); void PutLog(const CString& sLine, const CNick& Nick); @@ -66,10 +107,104 @@ public: private: CString m_sLogPath; bool m_bSanitize; + vector m_vRules; }; +void CLogMod::SetRulesCmd(const CString& sLine) +{ + VCString vsRules = SplitRules(sLine.Token(1, true)); + + if (vsRules.empty()) { + PutModule("Usage: SetRules "); + PutModule("Wildcards are allowed"); + } else { + SetRules(vsRules); + SetNV("rules", JoinRules(",")); + ListRulesCmd(); + } +} + +void CLogMod::ClearRulesCmd(const CString& sLine) +{ + size_t uCount = m_vRules.size(); + + if (uCount == 0) { + PutModule("No logging rules. Everything is logged."); + } else { + CString sRules = JoinRules(" "); + SetRules(VCString()); + DelNV("rules"); + PutModule(CString(uCount) + " rule(s) removed: " + sRules); + } +} + +void CLogMod::ListRulesCmd(const CString& sLine) +{ + CTable Table; + Table.AddColumn("Rule"); + Table.AddColumn("Logging enabled"); + + for (const CLogRule& Rule : m_vRules) { + Table.AddRow(); + Table.SetCell("Rule", Rule.GetRule()); + Table.SetCell("Logging enabled", CString(Rule.IsEnabled())); + } + + if (Table.empty()) { + PutModule("No logging rules. Everything is logged."); + } else { + PutModule(Table); + } +} + +void CLogMod::SetRules(const VCString& vsRules) +{ + m_vRules.clear(); + + for (CString sRule : vsRules) { + bool bEnabled = !sRule.TrimPrefix("!"); + m_vRules.push_back(CLogRule(sRule, bEnabled)); + } +} + +VCString CLogMod::SplitRules(const CString& sRules) const +{ + CString sCopy = sRules; + sCopy.Replace(",", " "); + + VCString vsRules; + sCopy.Split(" ", vsRules, false, "", "", true, true); + + return vsRules; +} + +CString CLogMod::JoinRules(const CString& sSeparator) const +{ + VCString vsRules; + for (const CLogRule& Rule : m_vRules) { + vsRules.push_back(Rule.ToString()); + } + + return sSeparator.Join(vsRules.begin(), vsRules.end()); +} + +bool CLogMod::TestRules(const CString& sTarget) const +{ + for (const CLogRule& Rule : m_vRules) { + if (Rule.Compare(sTarget)) { + return Rule.IsEnabled(); + } + } + + return true; +} + void CLogMod::PutLog(const CString& sLine, const CString& sWindow /*= "Status"*/) { + if (!TestRules(sWindow)) { + return; + } + CString sPath; time_t curtime; @@ -167,6 +302,10 @@ bool CLogMod::OnLoad(const CString& sArgs, CString& sMessage) } } + CString sRules = GetNV("rules"); + VCString vsRules = SplitRules(sRules); + SetRules(vsRules); + // Check if it's allowed to write in this path in general m_sLogPath = CDir::CheckPathPrefix(GetSavePath(), m_sLogPath); if (m_sLogPath.empty())