4c95583b6838d974c261c2c926c7b24b17d6d326
[platform/upstream/glog.git] / src / vlog_is_on.cc
1 // Copyright (c) 1999, 2007, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Ray Sidney and many others
31 //
32 // Broken out from logging.cc by Soren Lassen
33 // logging_unittest.cc covers the functionality herein
34
35 #include "utilities.h"
36
37 #include <string.h>
38 #include <stdlib.h>
39 #include <errno.h>
40 #include <cstdio>
41 #include <string>
42 #include "base/commandlineflags.h"
43 #include "glog/logging.h"
44 #include "glog/raw_logging.h"
45 #include "base/googleinit.h"
46
47 // glog doesn't have annotation
48 #define ANNOTATE_BENIGN_RACE(address, description)
49
50 using std::string;
51
52 GLOG_DEFINE_int32(v, 0, "Show all VLOG(m) messages for m <= this."
53 " Overridable by --vmodule.");
54
55 GLOG_DEFINE_string(vmodule, "", "per-module verbose level."
56 " Argument is a comma-separated list of <module name>=<log level>."
57 " <module name> is a glob pattern, matched against the filename base"
58 " (that is, name ignoring .cc/.h./-inl.h)."
59 " <log level> overrides any value given by --v.");
60
61 _START_GOOGLE_NAMESPACE_
62
63 namespace glog_internal_namespace_ {
64
65 // Implementation of fnmatch that does not need 0-termination
66 // of arguments and does not allocate any memory,
67 // but we only support "*" and "?" wildcards, not the "[...]" patterns.
68 // It's not a static function for the unittest.
69 GOOGLE_GLOG_DLL_DECL bool SafeFNMatch_(const char* pattern,
70                                        size_t patt_len,
71                                        const char* str,
72                                        size_t str_len) {
73   size_t p = 0;
74   size_t s = 0;
75   while (1) {
76     if (p == patt_len  &&  s == str_len) return true;
77     if (p == patt_len) return false;
78     if (s == str_len) return p+1 == patt_len  &&  pattern[p] == '*';
79     if (pattern[p] == str[s]  ||  pattern[p] == '?') {
80       p += 1;
81       s += 1;
82       continue;
83     }
84     if (pattern[p] == '*') {
85       if (p+1 == patt_len) return true;
86       do {
87         if (SafeFNMatch_(pattern+(p+1), patt_len-(p+1), str+s, str_len-s)) {
88           return true;
89         }
90         s += 1;
91       } while (s != str_len);
92       return false;
93     }
94     return false;
95   }
96 }
97
98 }  // namespace glog_internal_namespace_
99
100 using glog_internal_namespace_::SafeFNMatch_;
101
102 int32 kLogSiteUninitialized = 1000;
103
104 // List of per-module log levels from FLAGS_vmodule.
105 // Once created each element is never deleted/modified
106 // except for the vlog_level: other threads will read VModuleInfo blobs
107 // w/o locks and we'll store pointers to vlog_level at VLOG locations
108 // that will never go away.
109 // We can't use an STL struct here as we wouldn't know
110 // when it's safe to delete/update it: other threads need to use it w/o locks.
111 struct VModuleInfo {
112   string module_pattern;
113   mutable int32 vlog_level;  // Conceptually this is an AtomicWord, but it's
114                              // too much work to use AtomicWord type here
115                              // w/o much actual benefit.
116   const VModuleInfo* next;
117 };
118
119 // This protects the following global variables.
120 static Mutex vmodule_lock;
121 // Pointer to head of the VModuleInfo list.
122 // It's a map from module pattern to logging level for those module(s).
123 static VModuleInfo* vmodule_list = 0;
124 // Boolean initialization flag.
125 static bool inited_vmodule = false;
126
127 // L >= vmodule_lock.
128 static void VLOG2Initializer() {
129   vmodule_lock.AssertHeld();
130   // Can now parse --vmodule flag and initialize mapping of module-specific
131   // logging levels.
132   inited_vmodule = false;
133   const char* vmodule = FLAGS_vmodule.c_str();
134   const char* sep;
135   VModuleInfo* head = NULL;
136   VModuleInfo* tail = NULL;
137   while ((sep = strchr(vmodule, '=')) != NULL) {
138     string pattern(vmodule, sep - vmodule);
139     int module_level;
140     if (sscanf(sep, "=%d", &module_level) == 1) {
141       VModuleInfo* info = new VModuleInfo;
142       info->module_pattern = pattern;
143       info->vlog_level = module_level;
144       if (head)  tail->next = info;
145       else  head = info;
146       tail = info;
147     }
148     // Skip past this entry
149     vmodule = strchr(sep, ',');
150     if (vmodule == NULL) break;
151     vmodule++;  // Skip past ","
152   }
153   if (head) {  // Put them into the list at the head:
154     tail->next = vmodule_list;
155     vmodule_list = head;
156   }
157   inited_vmodule = true;
158 }
159
160 // This can be called very early, so we use SpinLock and RAW_VLOG here.
161 int SetVLOGLevel(const char* module_pattern, int log_level) {
162   int result = FLAGS_v;
163   int const pattern_len = strlen(module_pattern);
164   bool found = false;
165   {
166     MutexLock l(&vmodule_lock);  // protect whole read-modify-write
167     for (const VModuleInfo* info = vmodule_list;
168          info != NULL; info = info->next) {
169       if (info->module_pattern == module_pattern) {
170         if (!found) {
171           result = info->vlog_level;
172           found = true;
173         }
174         info->vlog_level = log_level;
175       } else if (!found  &&
176                  SafeFNMatch_(info->module_pattern.c_str(),
177                               info->module_pattern.size(),
178                               module_pattern, pattern_len)) {
179         result = info->vlog_level;
180         found = true;
181       }
182     }
183     if (!found) {
184       VModuleInfo* info = new VModuleInfo;
185       info->module_pattern = module_pattern;
186       info->vlog_level = log_level;
187       info->next = vmodule_list;
188       vmodule_list = info;
189     }
190   }
191   RAW_VLOG(1, "Set VLOG level for \"%s\" to %d", module_pattern, log_level);
192   return result;
193 }
194
195 // NOTE: Individual VLOG statements cache the integer log level pointers.
196 // NOTE: This function must not allocate memory or require any locks.
197 bool InitVLOG3__(int32** site_flag, int32* site_default,
198                  const char* fname, int32 verbose_level) {
199   MutexLock l(&vmodule_lock);
200   bool read_vmodule_flag = inited_vmodule;
201   if (!read_vmodule_flag) {
202     VLOG2Initializer();
203   }
204
205   // protect the errno global in case someone writes:
206   // VLOG(..) << "The last error was " << strerror(errno)
207   int old_errno = errno;
208
209   // site_default normally points to FLAGS_v
210   int32* site_flag_value = site_default;
211
212   // Get basename for file
213   const char* base = strrchr(fname, '/');
214   base = base ? (base+1) : fname;
215   const char* base_end = strchr(base, '.');
216   size_t base_length = base_end ? size_t(base_end - base) : strlen(base);
217
218   // Trim out trailing "-inl" if any
219   if (base_length >= 4 && (memcmp(base+base_length-4, "-inl", 4) == 0)) {
220     base_length -= 4;
221   }
222
223   // TODO: Trim out _unittest suffix?  Perhaps it is better to have
224   // the extra control and just leave it there.
225
226   // find target in vector of modules, replace site_flag_value with
227   // a module-specific verbose level, if any.
228   for (const VModuleInfo* info = vmodule_list;
229        info != NULL; info = info->next) {
230     if (SafeFNMatch_(info->module_pattern.c_str(), info->module_pattern.size(),
231                      base, base_length)) {
232       site_flag_value = &info->vlog_level;
233         // value at info->vlog_level is now what controls
234         // the VLOG at the caller site forever
235       break;
236     }
237   }
238
239   // Cache the vlog value pointer if --vmodule flag has been parsed.
240   ANNOTATE_BENIGN_RACE(site_flag,
241                        "*site_flag may be written by several threads,"
242                        " but the value will be the same");
243   if (read_vmodule_flag) *site_flag = site_flag_value;
244
245   // restore the errno in case something recoverable went wrong during
246   // the initialization of the VLOG mechanism (see above note "protect the..")
247   errno = old_errno;
248   return *site_flag_value >= verbose_level;
249 }
250
251 _END_GOOGLE_NAMESPACE_