13345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Copyright (c) 2010 The Chromium Authors. All rights reserved.
23345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Use of this source code is governed by a BSD-style license that can be
33345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// found in the LICENSE file.
43345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
53345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/vlog.h"
63345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
73345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/basictypes.h"
8513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch#include "base/logging.h"
93345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_split.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merricknamespace logging {
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst int VlogInfo::kDefaultVlogLevel = 0;
153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenstruct VlogInfo::VmodulePattern {
1772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  enum MatchTarget { MATCH_MODULE, MATCH_FILE };
1872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  explicit VmodulePattern(const std::string& pattern);
2072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
2172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  VmodulePattern();
2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  std::string pattern;
2472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int vlog_level;
2572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  MatchTarget match_target;
2672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen};
2772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
28513209b27ff55e2841eac0e4120199c23acce758Ben MurdochVlogInfo::VmodulePattern::VmodulePattern(const std::string& pattern)
29513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : pattern(pattern),
30513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      vlog_level(VlogInfo::kDefaultVlogLevel),
31513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      match_target(MATCH_MODULE) {
32513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // If the pattern contains a {forward,back} slash, we assume that
33513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // it's meant to be tested against the entire __FILE__ string.
34513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::string::size_type first_slash = pattern.find_first_of("\\/");
35513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (first_slash != std::string::npos)
36513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    match_target = MATCH_FILE;
37513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
38513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
39513209b27ff55e2841eac0e4120199c23acce758Ben MurdochVlogInfo::VmodulePattern::VmodulePattern()
40513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : vlog_level(VlogInfo::kDefaultVlogLevel),
41513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      match_target(MATCH_MODULE) {}
42513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickVlogInfo::VlogInfo(const std::string& v_switch,
44513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                   const std::string& vmodule_switch,
45513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                   int* min_log_level)
46513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    : min_log_level_(min_log_level) {
47513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  DCHECK(min_log_level != NULL);
48513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  typedef std::pair<std::string, std::string> KVPair;
50513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  int vlog_level = 0;
51201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch  if (!v_switch.empty()) {
52201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    if (base::StringToInt(v_switch, &vlog_level)) {
53201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      SetMaxVlogLevel(vlog_level);
54201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    } else {
55201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch      LOG(WARNING) << "Could not parse v switch \"" << v_switch << "\"";
56201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch    }
573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
58513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  std::vector<KVPair> kv_pairs;
603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!base::SplitStringIntoKeyValuePairs(
613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick          vmodule_switch, '=', ',', &kv_pairs)) {
623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    LOG(WARNING) << "Could not fully parse vmodule switch \""
633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                 << vmodule_switch << "\"";
643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (std::vector<KVPair>::const_iterator it = kv_pairs.begin();
663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick       it != kv_pairs.end(); ++it) {
67513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    VmodulePattern pattern(it->first);
68513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (!base::StringToInt(it->second, &pattern.vlog_level)) {
693345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      LOG(WARNING) << "Parsed vlog level for \""
703345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                   << it->first << "=" << it->second
71513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                   << "\" as " << pattern.vlog_level;
723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
73513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    vmodule_levels_.push_back(pattern);
743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
77731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickVlogInfo::~VlogInfo() {}
78731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
79513209b27ff55e2841eac0e4120199c23acce758Ben Murdochnamespace {
80513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
81513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Given a path, returns the basename with the extension chopped off
82513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// (and any -inl suffix).  We avoid using FilePath to minimize the
83513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// number of dependencies the logging system has.
84513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbase::StringPiece GetModule(const base::StringPiece& file) {
85513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::StringPiece module(file);
86513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::StringPiece::size_type last_slash_pos =
87513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      module.find_last_of("\\/");
88513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (last_slash_pos != base::StringPiece::npos)
89513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    module.remove_prefix(last_slash_pos + 1);
90513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::StringPiece::size_type extension_start = module.rfind('.');
91513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  module = module.substr(0, extension_start);
92513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  static const char kInlSuffix[] = "-inl";
93513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  static const int kInlSuffixLen = arraysize(kInlSuffix) - 1;
94513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (module.ends_with(kInlSuffix))
95513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    module.remove_suffix(kInlSuffixLen);
96513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return module;
97513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
98513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
99513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}  // namespace
100513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
101513209b27ff55e2841eac0e4120199c23acce758Ben Murdochint VlogInfo::GetVlogLevel(const base::StringPiece& file) const {
1023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!vmodule_levels_.empty()) {
103513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    base::StringPiece module(GetModule(file));
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    for (std::vector<VmodulePattern>::const_iterator it =
1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick             vmodule_levels_.begin(); it != vmodule_levels_.end(); ++it) {
106513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      base::StringPiece target(
107513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          (it->match_target == VmodulePattern::MATCH_FILE) ? file : module);
108513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      if (MatchVlogPattern(target, it->pattern))
109513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        return it->vlog_level;
110513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
111513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
112513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return GetMaxVlogLevel();
113513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch}
114513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid VlogInfo::SetMaxVlogLevel(int level) {
11672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Log severity is the negative verbosity.
11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  *min_log_level_ = -level;
11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
12072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenint VlogInfo::GetMaxVlogLevel() const {
12172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return -*min_log_level_;
12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
12372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
124513209b27ff55e2841eac0e4120199c23acce758Ben Murdochbool MatchVlogPattern(const base::StringPiece& string,
125513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                      const base::StringPiece& vlog_pattern) {
126513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::StringPiece p(vlog_pattern);
127513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  base::StringPiece s(string);
128513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Consume characters until the next star.
129513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  while (!p.empty() && !s.empty() && (p[0] != '*')) {
130513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    switch (p[0]) {
131513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // A slash (forward or back) must match a slash (forward or back).
132513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      case '/':
133513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      case '\\':
134513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        if ((s[0] != '/') && (s[0] != '\\'))
135513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          return false;
136513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        break;
137513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
138513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // A '?' matches anything.
139513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      case '?':
140513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        break;
141513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
142513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      // Anything else must match literally.
143513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      default:
144513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        if (p[0] != s[0])
145513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          return false;
146513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch        break;
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
148513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    p.remove_prefix(1), s.remove_prefix(1);
1493345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
150513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
151513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // An empty pattern here matches only an empty string.
152513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (p.empty())
153513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return s.empty();
154513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
155513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Coalesce runs of consecutive stars.  There should be at least
156513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // one.
157513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  while (!p.empty() && (p[0] == '*'))
158513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    p.remove_prefix(1);
159513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
160513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Since we moved past the stars, an empty pattern here matches
161513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // anything.
162513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (p.empty())
163513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    return true;
164513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
165513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Since we moved past the stars and p is non-empty, if some
166513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // non-empty substring of s matches p, then we ourselves match.
167513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  while (!s.empty()) {
168513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (MatchVlogPattern(s, p))
169513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      return true;
170513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    s.remove_prefix(1);
171513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  }
172513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
173513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  // Otherwise, we couldn't find a match.
174513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  return false;
1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
1763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}  // namespace
178