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