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