vlog.cc revision 201ade2fbba22bfb27ae029f4d23fca6ded109a0
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/vlog.h" 6 7#include "base/basictypes.h" 8#include "base/logging.h" 9#include "base/string_number_conversions.h" 10#include "base/string_split.h" 11 12namespace logging { 13 14const int VlogInfo::kDefaultVlogLevel = 0; 15 16VlogInfo::VmodulePattern::VmodulePattern(const std::string& pattern) 17 : pattern(pattern), 18 vlog_level(VlogInfo::kDefaultVlogLevel), 19 match_target(MATCH_MODULE) { 20 // If the pattern contains a {forward,back} slash, we assume that 21 // it's meant to be tested against the entire __FILE__ string. 22 std::string::size_type first_slash = pattern.find_first_of("\\/"); 23 if (first_slash != std::string::npos) 24 match_target = MATCH_FILE; 25} 26 27VlogInfo::VmodulePattern::VmodulePattern() 28 : vlog_level(VlogInfo::kDefaultVlogLevel), 29 match_target(MATCH_MODULE) {} 30 31VlogInfo::VlogInfo(const std::string& v_switch, 32 const std::string& vmodule_switch, 33 int* min_log_level) 34 : min_log_level_(min_log_level) { 35 DCHECK(min_log_level != NULL); 36 37 typedef std::pair<std::string, std::string> KVPair; 38 int vlog_level = 0; 39 if (!v_switch.empty()) { 40 if (base::StringToInt(v_switch, &vlog_level)) { 41 SetMaxVlogLevel(vlog_level); 42 } else { 43 LOG(WARNING) << "Could not parse v switch \"" << v_switch << "\""; 44 } 45 } 46 47 std::vector<KVPair> kv_pairs; 48 if (!base::SplitStringIntoKeyValuePairs( 49 vmodule_switch, '=', ',', &kv_pairs)) { 50 LOG(WARNING) << "Could not fully parse vmodule switch \"" 51 << vmodule_switch << "\""; 52 } 53 for (std::vector<KVPair>::const_iterator it = kv_pairs.begin(); 54 it != kv_pairs.end(); ++it) { 55 VmodulePattern pattern(it->first); 56 if (!base::StringToInt(it->second, &pattern.vlog_level)) { 57 LOG(WARNING) << "Parsed vlog level for \"" 58 << it->first << "=" << it->second 59 << "\" as " << pattern.vlog_level; 60 } 61 vmodule_levels_.push_back(pattern); 62 } 63} 64 65VlogInfo::~VlogInfo() {} 66 67void VlogInfo::SetMaxVlogLevel(int level) { 68 // Log severity is the negative verbosity. 69 *min_log_level_ = -level; 70} 71 72int VlogInfo::GetMaxVlogLevel() const { 73 return -*min_log_level_; 74} 75 76namespace { 77 78// Given a path, returns the basename with the extension chopped off 79// (and any -inl suffix). We avoid using FilePath to minimize the 80// number of dependencies the logging system has. 81base::StringPiece GetModule(const base::StringPiece& file) { 82 base::StringPiece module(file); 83 base::StringPiece::size_type last_slash_pos = 84 module.find_last_of("\\/"); 85 if (last_slash_pos != base::StringPiece::npos) 86 module.remove_prefix(last_slash_pos + 1); 87 base::StringPiece::size_type extension_start = module.rfind('.'); 88 module = module.substr(0, extension_start); 89 static const char kInlSuffix[] = "-inl"; 90 static const int kInlSuffixLen = arraysize(kInlSuffix) - 1; 91 if (module.ends_with(kInlSuffix)) 92 module.remove_suffix(kInlSuffixLen); 93 return module; 94} 95 96} // namespace 97 98int VlogInfo::GetVlogLevel(const base::StringPiece& file) const { 99 if (!vmodule_levels_.empty()) { 100 base::StringPiece module(GetModule(file)); 101 for (std::vector<VmodulePattern>::const_iterator it = 102 vmodule_levels_.begin(); it != vmodule_levels_.end(); ++it) { 103 base::StringPiece target( 104 (it->match_target == VmodulePattern::MATCH_FILE) ? file : module); 105 if (MatchVlogPattern(target, it->pattern)) 106 return it->vlog_level; 107 } 108 } 109 return GetMaxVlogLevel(); 110} 111 112bool MatchVlogPattern(const base::StringPiece& string, 113 const base::StringPiece& vlog_pattern) { 114 base::StringPiece p(vlog_pattern); 115 base::StringPiece s(string); 116 // Consume characters until the next star. 117 while (!p.empty() && !s.empty() && (p[0] != '*')) { 118 switch (p[0]) { 119 // A slash (forward or back) must match a slash (forward or back). 120 case '/': 121 case '\\': 122 if ((s[0] != '/') && (s[0] != '\\')) 123 return false; 124 break; 125 126 // A '?' matches anything. 127 case '?': 128 break; 129 130 // Anything else must match literally. 131 default: 132 if (p[0] != s[0]) 133 return false; 134 break; 135 } 136 p.remove_prefix(1), s.remove_prefix(1); 137 } 138 139 // An empty pattern here matches only an empty string. 140 if (p.empty()) 141 return s.empty(); 142 143 // Coalesce runs of consecutive stars. There should be at least 144 // one. 145 while (!p.empty() && (p[0] == '*')) 146 p.remove_prefix(1); 147 148 // Since we moved past the stars, an empty pattern here matches 149 // anything. 150 if (p.empty()) 151 return true; 152 153 // Since we moved past the stars and p is non-empty, if some 154 // non-empty substring of s matches p, then we ourselves match. 155 while (!s.empty()) { 156 if (MatchVlogPattern(s, p)) 157 return true; 158 s.remove_prefix(1); 159 } 160 161 // Otherwise, we couldn't find a match. 162 return false; 163} 164 165} // namespace 166