OR-Tools  9.3
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"
29
30ABSL_FLAG(int, v, 0,
31 "Show all VLOG(m) messages for m <= this."
32 " Overridable by --vmodule.");
33
34ABSL_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
41namespace google {
42
43namespace logging_internal {
44
45// Used by logging_unittests.cc so can't make it static here.
46GOOGLE_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.
53GOOGLE_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
85int32_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.
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.
100};
101
102// This protects the following global variables.
103static 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.
108static bool inited_vmodule = false;
109
110// L >= vmodule_lock.
111static 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 = nullptr;
120 VModuleInfo* tail = nullptr;
121 while ((sep = strchr(vmodule, '=')) != nullptr) {
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 == nullptr) break;
137 vmodule++; // Skip past ","
138 }
139 if (head) { // Put them into the list at the head:
140 tail->next = vmodule_list;
142 }
143 inited_vmodule = true;
144}
145
146// This can be called very early, so we use SpinLock and RAW_VLOG here.
147int 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 != nullptr;
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.
182bool 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 != nullptr;
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
#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:53
int32_t kLogSiteUninitialized
Definition: vlog_is_on.cc:85
static absl::Mutex vmodule_lock
Definition: vlog_is_on.cc:103
static bool inited_vmodule
Definition: vlog_is_on.cc:108
static VModuleInfo * vmodule_list
Definition: vlog_is_on.cc:106
static void VLOG2Initializer()
Definition: vlog_is_on.cc:111
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
#define RAW_VLOG(verboselevel,...)
Definition: raw_logging.h:59
int64_t tail
int64_t head
std::string module_pattern
Definition: vlog_is_on.cc:95
const VModuleInfo * next
Definition: vlog_is_on.cc:99
ABSL_FLAG(int, v, 0, "Show all VLOG(m) messages for m <= this." " Overridable by --vmodule.")