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