glog 0.1
[platform/upstream/glog.git] / src / vlog_is_on.cc
1 // Copyright 1999, 2007 Google Inc. All Rights Reserved.
2 // Author: Ray Sidney and many others
3 // Broken out from logging.cc by Soren Lassen
4 // logging_unittest.cc covers the functionality herein
5
6 #include "utilities.h"
7
8 #include <string.h>
9 #include <stdlib.h>
10 #include <errno.h>
11 #include <fnmatch.h>  // fnmatch() is used in obsolete _InitVLOG
12 #include <cstdio>
13 #include <string>
14 #include "base/commandlineflags.h"
15 #include "glog/logging.h"
16 #include "glog/raw_logging.h"
17 #include "base/googleinit.h"
18
19 // glog doesn't have annotation
20 #define ANNOTATE_BENIGN_RACE(address, description)
21
22 using std::string;
23
24 DEFINE_int32(v, 0, "Show all VLOG(m) messages for m <= this."
25 " Overridable by --vmodule.");
26
27 DEFINE_string(vmodule, "", "per-module verbose level."
28 " Argument is a comma-separated list of <module name>=<log level>."
29 " <module name> is a glob pattern, matched against the filename base"
30 " (that is, name ignoring .cc/.h./-inl.h)."
31 " <log level> overrides any value given by --v.");
32
33 _START_GOOGLE_NAMESPACE_
34
35 // Implementation of fnmatch that does not need 0-termination
36 // of arguments and does not allocate any memory,
37 // but we only support "*" and "?" wildcards, not the "[...]" patterns.
38 // It's not a static function for the unittest.
39 bool SafeFNMatch_(const char* pattern, size_t patt_len,
40                   const char* str, size_t str_len) {
41   int p = 0;
42   int s = 0;
43   while (1) {
44     if (p == patt_len  &&  s == str_len) return true;
45     if (p == patt_len) return false;
46     if (s == str_len) return p+1 == patt_len  &&  pattern[p] == '*';
47     if (pattern[p] == str[s]  ||  pattern[p] == '?') {
48       p += 1;
49       s += 1;
50       continue;
51     }
52     if (pattern[p] == '*') {
53       if (p+1 == patt_len) return true;
54       do {
55         if (SafeFNMatch_(pattern+(p+1), patt_len-(p+1), str+s, str_len-s)) {
56           return true;
57         }
58         s += 1;
59       } while (s != str_len);
60       return false;
61     }
62     return false;
63   }
64 }
65
66 int32 kLogSiteUninitialized = 1000;
67
68 // List of per-module log levels from FLAGS_vmodule.
69 // Once created each element is never deleted/modified
70 // except for the vlog_level: other threads will read VModuleInfo blobs
71 // w/o locks and we'll store pointers to vlog_level at VLOG locations
72 // that will never go away.
73 // We can't use an STL struct here as we wouldn't know
74 // when it's safe to delete/update it: other threads need to use it w/o locks.
75 struct VModuleInfo {
76   string module_pattern;
77   mutable int32 vlog_level;  // Conceptually this is an AtomicWord, but it's
78                              // too much work to use AtomicWord type here
79                              // w/o much actual benefit.
80   const VModuleInfo* next;
81 };
82
83 // This protects the following global variables.
84 static Mutex vmodule_lock;
85 // Pointer to head of the VModuleInfo list.
86 // It's a map from module pattern to logging level for those module(s).
87 static VModuleInfo* vmodule_list = 0;
88 // Boolean initialization flag.
89 static bool inited_vmodule = false;
90
91 static void VLOG2Initializer() {
92   MutexLock l(&vmodule_lock);
93   // Can now parse --vmodule flag and initialize mapping of module-specific
94   // logging levels.
95   inited_vmodule = false;
96   const char* vmodule = FLAGS_vmodule.c_str();
97   const char* sep;
98   VModuleInfo* head = NULL;
99   VModuleInfo* tail = NULL;
100   while ((sep = strchr(vmodule, '=')) != NULL) {
101     string pattern(vmodule, sep - vmodule);
102     int module_level;
103     if (sscanf(sep, "=%d", &module_level) == 1) {
104       VModuleInfo* info = new VModuleInfo;
105       info->module_pattern = pattern;
106       info->vlog_level = module_level;
107       if (head)  tail->next = info;
108       else  head = info;
109       tail = info;
110     }
111     // Skip past this entry
112     vmodule = strchr(sep, ',');
113     if (vmodule == NULL) break;
114     vmodule++;  // Skip past ","
115   }
116   if (head) {  // Put them into the list at the head:
117     tail->next = vmodule_list;
118     vmodule_list = head;
119   }
120   inited_vmodule = true;
121 }
122
123 REGISTER_MODULE_INITIALIZER(vlog_is_on, VLOG2Initializer());
124
125 // This can be called very early, so we use SpinLock and RAW_VLOG here.
126 int SetVLOGLevel(const char* module_pattern, int log_level) {
127   int result = FLAGS_v;
128   int const pattern_len = strlen(module_pattern);
129   bool found = false;
130   MutexLock l(&vmodule_lock);  // protect whole read-modify-write
131   for (const VModuleInfo* info = vmodule_list;
132        info != NULL; info = info->next) {
133     if (info->module_pattern == module_pattern) {
134       if (!found) {
135         result = info->vlog_level;
136         found = true;
137       }
138       info->vlog_level = log_level;
139     } else if (!found  &&
140                SafeFNMatch_(info->module_pattern.c_str(),
141                             info->module_pattern.size(),
142                             module_pattern, pattern_len)) {
143       result = info->vlog_level;
144       found = true;
145     }
146   }
147   if (!found) {
148     VModuleInfo* info = new VModuleInfo;
149     info->module_pattern = module_pattern;
150     info->vlog_level = log_level;
151     info->next = vmodule_list;
152     vmodule_list = info;
153   }
154   RAW_VLOG(1, "Set VLOG level for \"%s\" to %d", module_pattern, log_level);
155   return result;
156 }
157
158 // NOTE: Individual VLOG statements cache the integer log level pointers.
159 // NOTE: This function must not allocate memory or require any locks.
160 bool InitVLOG3__(int32** site_flag, int32* site_default,
161                  const char* fname, int32 verbose_level) {
162   MutexLock l(&vmodule_lock);
163   bool read_vmodule_flag = inited_vmodule;
164   if (!read_vmodule_flag  &&  vmodule_list == 0) {
165     // The command line --vmodule flags haven't been parsed
166     // and nothing was set with SetVLOGLevel yet,
167     // but *site_default (usually FLAGS_v) might be manually set
168     // by some early-executing code, or else it's still 0.
169     return *site_default >= verbose_level;
170   }
171
172   // protect the errno global in case someone writes:
173   // VLOG(..) << "The last error was " << strerror(errno)
174   int old_errno = errno;
175
176   // site_default normally points to FLAGS_v
177   int32* site_flag_value = site_default;
178
179   // Get basename for file
180   const char* base = strrchr(fname, '/');
181   base = base ? (base+1) : fname;
182   const char* base_end = strchr(base, '.');
183   size_t base_length = base_end ? (base_end - base) : strlen(base);
184
185   // Trim out trailing "-inl" if any
186   if (base_length >= 4 && (memcmp(base+base_length-4, "-inl", 4) == 0)) {
187     base_length -= 4;
188   }
189
190   // TODO: Trim out _unittest suffix?  Perhaps it is better to have
191   // the extra control and just leave it there.
192
193   // find target in vector of modules, replace site_flag_value with
194   // a module-specific verbose level, if any.
195   for (const VModuleInfo* info = vmodule_list;
196        info != NULL; info = info->next) {
197     if (SafeFNMatch_(info->module_pattern.c_str(), info->module_pattern.size(),
198                      base, base_length)) {
199       site_flag_value = &info->vlog_level;
200         // value at info->vlog_level is now what controls
201         // the VLOG at the caller site forever
202       break;
203     }
204   }
205
206   // Cache the vlog value pointer if --vmodule flag has been parsed.
207   ANNOTATE_BENIGN_RACE(site_flag,
208                        "*site_flag may be written by several threads,"
209                        " but the value will be the same");
210   if (read_vmodule_flag) *site_flag = site_flag_value;
211
212   // restore the errno in case something recoverable went wrong during
213   // the initialization of the VLOG mechanism (see above note "protect the..")
214   errno = old_errno;
215   return *site_flag_value >= verbose_level;
216 }
217
218 _END_GOOGLE_NAMESPACE_