summaryrefslogtreecommitdiffstats
path: root/base/vlog.cc
diff options
context:
space:
mode:
Diffstat (limited to 'base/vlog.cc')
-rw-r--r--base/vlog.cc151
1 files changed, 122 insertions, 29 deletions
diff --git a/base/vlog.cc b/base/vlog.cc
index 6075b0b..cda9cea 100644
--- a/base/vlog.cc
+++ b/base/vlog.cc
@@ -5,22 +5,44 @@
#include "base/vlog.h"
#include "base/basictypes.h"
+#include "base/logging.h"
#include "base/string_number_conversions.h"
#include "base/string_split.h"
-#include "base/string_util.h"
namespace logging {
const int VlogInfo::kDefaultVlogLevel = 0;
+VlogInfo::VmodulePattern::VmodulePattern(const std::string& pattern)
+ : pattern(pattern),
+ vlog_level(VlogInfo::kDefaultVlogLevel),
+ match_target(MATCH_MODULE) {
+ // If the pattern contains a {forward,back} slash, we assume that
+ // it's meant to be tested against the entire __FILE__ string.
+ std::string::size_type first_slash = pattern.find_first_of("\\/");
+ if (first_slash != std::string::npos)
+ match_target = MATCH_FILE;
+}
+
+VlogInfo::VmodulePattern::VmodulePattern()
+ : vlog_level(VlogInfo::kDefaultVlogLevel),
+ match_target(MATCH_MODULE) {}
+
VlogInfo::VlogInfo(const std::string& v_switch,
- const std::string& vmodule_switch)
- : max_vlog_level_(kDefaultVlogLevel) {
+ const std::string& vmodule_switch,
+ int* min_log_level)
+ : min_log_level_(min_log_level) {
+ DCHECK(min_log_level != NULL);
+
typedef std::pair<std::string, std::string> KVPair;
- if (!base::StringToInt(v_switch, &max_vlog_level_)) {
+ int vlog_level = 0;
+ if (base::StringToInt(v_switch, &vlog_level)) {
+ SetMaxVlogLevel(vlog_level);
+ } else {
LOG(WARNING) << "Parsed v switch \""
- << v_switch << "\" as " << max_vlog_level_;
+ << v_switch << "\" as " << vlog_level;
}
+
std::vector<KVPair> kv_pairs;
if (!base::SplitStringIntoKeyValuePairs(
vmodule_switch, '=', ',', &kv_pairs)) {
@@ -29,43 +51,114 @@ VlogInfo::VlogInfo(const std::string& v_switch,
}
for (std::vector<KVPair>::const_iterator it = kv_pairs.begin();
it != kv_pairs.end(); ++it) {
- int vlog_level = kDefaultVlogLevel;
- if (!base::StringToInt(it->second, &vlog_level)) {
+ VmodulePattern pattern(it->first);
+ if (!base::StringToInt(it->second, &pattern.vlog_level)) {
LOG(WARNING) << "Parsed vlog level for \""
<< it->first << "=" << it->second
- << "\" as " << vlog_level;
+ << "\" as " << pattern.vlog_level;
}
- vmodule_levels_.push_back(std::make_pair(it->first, vlog_level));
+ vmodule_levels_.push_back(pattern);
}
}
VlogInfo::~VlogInfo() {}
-int VlogInfo::GetVlogLevel(const base::StringPiece& file) {
+void VlogInfo::SetMaxVlogLevel(int level) {
+ // Log severity is the negative verbosity.
+ *min_log_level_ = -level;
+}
+
+int VlogInfo::GetMaxVlogLevel() const {
+ return -*min_log_level_;
+}
+
+namespace {
+
+// Given a path, returns the basename with the extension chopped off
+// (and any -inl suffix). We avoid using FilePath to minimize the
+// number of dependencies the logging system has.
+base::StringPiece GetModule(const base::StringPiece& file) {
+ base::StringPiece module(file);
+ base::StringPiece::size_type last_slash_pos =
+ module.find_last_of("\\/");
+ if (last_slash_pos != base::StringPiece::npos)
+ module.remove_prefix(last_slash_pos + 1);
+ base::StringPiece::size_type extension_start = module.rfind('.');
+ module = module.substr(0, extension_start);
+ static const char kInlSuffix[] = "-inl";
+ static const int kInlSuffixLen = arraysize(kInlSuffix) - 1;
+ if (module.ends_with(kInlSuffix))
+ module.remove_suffix(kInlSuffixLen);
+ return module;
+}
+
+} // namespace
+
+int VlogInfo::GetVlogLevel(const base::StringPiece& file) const {
if (!vmodule_levels_.empty()) {
- base::StringPiece module(file);
- base::StringPiece::size_type last_slash_pos =
- module.find_last_of("\\/");
- if (last_slash_pos != base::StringPiece::npos) {
- module.remove_prefix(last_slash_pos + 1);
- }
- base::StringPiece::size_type extension_start = module.find('.');
- module = module.substr(0, extension_start);
- static const char kInlSuffix[] = "-inl";
- static const int kInlSuffixLen = arraysize(kInlSuffix) - 1;
- if (module.ends_with(kInlSuffix)) {
- module.remove_suffix(kInlSuffixLen);
- }
+ base::StringPiece module(GetModule(file));
for (std::vector<VmodulePattern>::const_iterator it =
vmodule_levels_.begin(); it != vmodule_levels_.end(); ++it) {
- // TODO(akalin): Use a less-heavyweight version of MatchPattern
- // (we can pretty much assume we're dealing with ASCII).
- if (MatchPattern(module, it->first)) {
- return it->second;
- }
+ base::StringPiece target(
+ (it->match_target == VmodulePattern::MATCH_FILE) ? file : module);
+ if (MatchVlogPattern(target, it->pattern))
+ return it->vlog_level;
+ }
+ }
+ return GetMaxVlogLevel();
+}
+
+bool MatchVlogPattern(const base::StringPiece& string,
+ const base::StringPiece& vlog_pattern) {
+ base::StringPiece p(vlog_pattern);
+ base::StringPiece s(string);
+ // Consume characters until the next star.
+ while (!p.empty() && !s.empty() && (p[0] != '*')) {
+ switch (p[0]) {
+ // A slash (forward or back) must match a slash (forward or back).
+ case '/':
+ case '\\':
+ if ((s[0] != '/') && (s[0] != '\\'))
+ return false;
+ break;
+
+ // A '?' matches anything.
+ case '?':
+ break;
+
+ // Anything else must match literally.
+ default:
+ if (p[0] != s[0])
+ return false;
+ break;
}
+ p.remove_prefix(1), s.remove_prefix(1);
}
- return max_vlog_level_;
+
+ // An empty pattern here matches only an empty string.
+ if (p.empty())
+ return s.empty();
+
+ // Coalesce runs of consecutive stars. There should be at least
+ // one.
+ while (!p.empty() && (p[0] == '*'))
+ p.remove_prefix(1);
+
+ // Since we moved past the stars, an empty pattern here matches
+ // anything.
+ if (p.empty())
+ return true;
+
+ // Since we moved past the stars and p is non-empty, if some
+ // non-empty substring of s matches p, then we ourselves match.
+ while (!s.empty()) {
+ if (MatchVlogPattern(s, p))
+ return true;
+ s.remove_prefix(1);
+ }
+
+ // Otherwise, we couldn't find a match.
+ return false;
}
} // namespace