Blame src/vlog_is_on.cc

Packit 18d29c
// Copyright (c) 1999, 2007, Google Inc.
Packit 18d29c
// All rights reserved.
Packit 18d29c
//
Packit 18d29c
// Redistribution and use in source and binary forms, with or without
Packit 18d29c
// modification, are permitted provided that the following conditions are
Packit 18d29c
// met:
Packit 18d29c
//
Packit 18d29c
//     * Redistributions of source code must retain the above copyright
Packit 18d29c
// notice, this list of conditions and the following disclaimer.
Packit 18d29c
//     * Redistributions in binary form must reproduce the above
Packit 18d29c
// copyright notice, this list of conditions and the following disclaimer
Packit 18d29c
// in the documentation and/or other materials provided with the
Packit 18d29c
// distribution.
Packit 18d29c
//     * Neither the name of Google Inc. nor the names of its
Packit 18d29c
// contributors may be used to endorse or promote products derived from
Packit 18d29c
// this software without specific prior written permission.
Packit 18d29c
//
Packit 18d29c
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 18d29c
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 18d29c
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 18d29c
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 18d29c
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 18d29c
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 18d29c
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 18d29c
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 18d29c
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 18d29c
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 18d29c
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 18d29c
//
Packit 18d29c
// Author: Ray Sidney and many others
Packit 18d29c
//
Packit 18d29c
// Broken out from logging.cc by Soren Lassen
Packit 18d29c
// logging_unittest.cc covers the functionality herein
Packit 18d29c
Packit 18d29c
#include "utilities.h"
Packit 18d29c
Packit 18d29c
#include <string.h>
Packit 18d29c
#include <stdlib.h>
Packit 18d29c
#include <errno.h>
Packit 18d29c
#include <cstdio>
Packit 18d29c
#include <string>
Packit 18d29c
#include "base/commandlineflags.h"
Packit 18d29c
#include "glog/logging.h"
Packit 18d29c
#include "glog/raw_logging.h"
Packit 18d29c
#include "base/googleinit.h"
Packit 18d29c
Packit 18d29c
// glog doesn't have annotation
Packit 18d29c
#define ANNOTATE_BENIGN_RACE(address, description)
Packit 18d29c
Packit 18d29c
using std::string;
Packit 18d29c
Packit 18d29c
GLOG_DEFINE_int32(v, 0, "Show all VLOG(m) messages for m <= this."
Packit 18d29c
" Overridable by --vmodule.");
Packit 18d29c
Packit 18d29c
GLOG_DEFINE_string(vmodule, "", "per-module verbose level."
Packit 18d29c
" Argument is a comma-separated list of <module name>=<log level>."
Packit 18d29c
" <module name> is a glob pattern, matched against the filename base"
Packit 18d29c
" (that is, name ignoring .cc/.h./-inl.h)."
Packit 18d29c
" <log level> overrides any value given by --v.");
Packit 18d29c
Packit 18d29c
_START_GOOGLE_NAMESPACE_
Packit 18d29c
Packit 18d29c
namespace glog_internal_namespace_ {
Packit 18d29c
Packit 18d29c
// Implementation of fnmatch that does not need 0-termination
Packit 18d29c
// of arguments and does not allocate any memory,
Packit 18d29c
// but we only support "*" and "?" wildcards, not the "[...]" patterns.
Packit 18d29c
// It's not a static function for the unittest.
Packit 18d29c
GOOGLE_GLOG_DLL_DECL bool SafeFNMatch_(const char* pattern,
Packit 18d29c
                                       size_t patt_len,
Packit 18d29c
                                       const char* str,
Packit 18d29c
                                       size_t str_len) {
Packit 18d29c
  size_t p = 0;
Packit 18d29c
  size_t s = 0;
Packit 18d29c
  while (1) {
Packit 18d29c
    if (p == patt_len  &&  s == str_len) return true;
Packit 18d29c
    if (p == patt_len) return false;
Packit 18d29c
    if (s == str_len) return p+1 == patt_len  &&  pattern[p] == '*';
Packit 18d29c
    if (pattern[p] == str[s]  ||  pattern[p] == '?') {
Packit 18d29c
      p += 1;
Packit 18d29c
      s += 1;
Packit 18d29c
      continue;
Packit 18d29c
    }
Packit 18d29c
    if (pattern[p] == '*') {
Packit 18d29c
      if (p+1 == patt_len) return true;
Packit 18d29c
      do {
Packit 18d29c
        if (SafeFNMatch_(pattern+(p+1), patt_len-(p+1), str+s, str_len-s)) {
Packit 18d29c
          return true;
Packit 18d29c
        }
Packit 18d29c
        s += 1;
Packit 18d29c
      } while (s != str_len);
Packit 18d29c
      return false;
Packit 18d29c
    }
Packit 18d29c
    return false;
Packit 18d29c
  }
Packit 18d29c
}
Packit 18d29c
Packit 18d29c
}  // namespace glog_internal_namespace_
Packit 18d29c
Packit 18d29c
using glog_internal_namespace_::SafeFNMatch_;
Packit 18d29c
Packit 18d29c
int32 kLogSiteUninitialized = 1000;
Packit 18d29c
Packit 18d29c
// List of per-module log levels from FLAGS_vmodule.
Packit 18d29c
// Once created each element is never deleted/modified
Packit 18d29c
// except for the vlog_level: other threads will read VModuleInfo blobs
Packit 18d29c
// w/o locks and we'll store pointers to vlog_level at VLOG locations
Packit 18d29c
// that will never go away.
Packit 18d29c
// We can't use an STL struct here as we wouldn't know
Packit 18d29c
// when it's safe to delete/update it: other threads need to use it w/o locks.
Packit 18d29c
struct VModuleInfo {
Packit 18d29c
  string module_pattern;
Packit 18d29c
  mutable int32 vlog_level;  // Conceptually this is an AtomicWord, but it's
Packit 18d29c
                             // too much work to use AtomicWord type here
Packit 18d29c
                             // w/o much actual benefit.
Packit 18d29c
  const VModuleInfo* next;
Packit 18d29c
};
Packit 18d29c
Packit 18d29c
// This protects the following global variables.
Packit 18d29c
static Mutex vmodule_lock;
Packit 18d29c
// Pointer to head of the VModuleInfo list.
Packit 18d29c
// It's a map from module pattern to logging level for those module(s).
Packit 18d29c
static VModuleInfo* vmodule_list = 0;
Packit 18d29c
// Boolean initialization flag.
Packit 18d29c
static bool inited_vmodule = false;
Packit 18d29c
Packit 18d29c
// L >= vmodule_lock.
Packit 18d29c
static void VLOG2Initializer() {
Packit 18d29c
  vmodule_lock.AssertHeld();
Packit 18d29c
  // Can now parse --vmodule flag and initialize mapping of module-specific
Packit 18d29c
  // logging levels.
Packit 18d29c
  inited_vmodule = false;
Packit 18d29c
  const char* vmodule = FLAGS_vmodule.c_str();
Packit 18d29c
  const char* sep;
Packit 18d29c
  VModuleInfo* head = NULL;
Packit 18d29c
  VModuleInfo* tail = NULL;
Packit 18d29c
  while ((sep = strchr(vmodule, '=')) != NULL) {
Packit 18d29c
    string pattern(vmodule, sep - vmodule);
Packit 18d29c
    int module_level;
Packit 18d29c
    if (sscanf(sep, "=%d", &module_level) == 1) {
Packit 18d29c
      VModuleInfo* info = new VModuleInfo;
Packit 18d29c
      info->module_pattern = pattern;
Packit 18d29c
      info->vlog_level = module_level;
Packit 18d29c
      if (head)  tail->next = info;
Packit 18d29c
      else  head = info;
Packit 18d29c
      tail = info;
Packit 18d29c
    }
Packit 18d29c
    // Skip past this entry
Packit 18d29c
    vmodule = strchr(sep, ',');
Packit 18d29c
    if (vmodule == NULL) break;
Packit 18d29c
    vmodule++;  // Skip past ","
Packit 18d29c
  }
Packit 18d29c
  if (head) {  // Put them into the list at the head:
Packit 18d29c
    tail->next = vmodule_list;
Packit 18d29c
    vmodule_list = head;
Packit 18d29c
  }
Packit 18d29c
  inited_vmodule = true;
Packit 18d29c
}
Packit 18d29c
Packit 18d29c
// This can be called very early, so we use SpinLock and RAW_VLOG here.
Packit 18d29c
int SetVLOGLevel(const char* module_pattern, int log_level) {
Packit 18d29c
  int result = FLAGS_v;
Packit 18d29c
  int const pattern_len = strlen(module_pattern);
Packit 18d29c
  bool found = false;
Packit 18d29c
  {
Packit 18d29c
    MutexLock l(&vmodule_lock);  // protect whole read-modify-write
Packit 18d29c
    for (const VModuleInfo* info = vmodule_list;
Packit 18d29c
         info != NULL; info = info->next) {
Packit 18d29c
      if (info->module_pattern == module_pattern) {
Packit 18d29c
        if (!found) {
Packit 18d29c
          result = info->vlog_level;
Packit 18d29c
          found = true;
Packit 18d29c
        }
Packit 18d29c
        info->vlog_level = log_level;
Packit 18d29c
      } else if (!found  &&
Packit 18d29c
                 SafeFNMatch_(info->module_pattern.c_str(),
Packit 18d29c
                              info->module_pattern.size(),
Packit 18d29c
                              module_pattern, pattern_len)) {
Packit 18d29c
        result = info->vlog_level;
Packit 18d29c
        found = true;
Packit 18d29c
      }
Packit 18d29c
    }
Packit 18d29c
    if (!found) {
Packit 18d29c
      VModuleInfo* info = new VModuleInfo;
Packit 18d29c
      info->module_pattern = module_pattern;
Packit 18d29c
      info->vlog_level = log_level;
Packit 18d29c
      info->next = vmodule_list;
Packit 18d29c
      vmodule_list = info;
Packit 18d29c
    }
Packit 18d29c
  }
Packit 18d29c
  RAW_VLOG(1, "Set VLOG level for \"%s\" to %d", module_pattern, log_level);
Packit 18d29c
  return result;
Packit 18d29c
}
Packit 18d29c
Packit 18d29c
// NOTE: Individual VLOG statements cache the integer log level pointers.
Packit 18d29c
// NOTE: This function must not allocate memory or require any locks.
Packit 18d29c
bool InitVLOG3__(int32** site_flag, int32* site_default,
Packit 18d29c
                 const char* fname, int32 verbose_level) {
Packit 18d29c
  MutexLock l(&vmodule_lock);
Packit 18d29c
  bool read_vmodule_flag = inited_vmodule;
Packit 18d29c
  if (!read_vmodule_flag) {
Packit 18d29c
    VLOG2Initializer();
Packit 18d29c
  }
Packit 18d29c
Packit 18d29c
  // protect the errno global in case someone writes:
Packit 18d29c
  // VLOG(..) << "The last error was " << strerror(errno)
Packit 18d29c
  int old_errno = errno;
Packit 18d29c
Packit 18d29c
  // site_default normally points to FLAGS_v
Packit 18d29c
  int32* site_flag_value = site_default;
Packit 18d29c
Packit 18d29c
  // Get basename for file
Packit 18d29c
  const char* base = strrchr(fname, '/');
Packit 18d29c
  base = base ? (base+1) : fname;
Packit 18d29c
  const char* base_end = strchr(base, '.');
Packit 18d29c
  size_t base_length = base_end ? size_t(base_end - base) : strlen(base);
Packit 18d29c
Packit 18d29c
  // Trim out trailing "-inl" if any
Packit 18d29c
  if (base_length >= 4 && (memcmp(base+base_length-4, "-inl", 4) == 0)) {
Packit 18d29c
    base_length -= 4;
Packit 18d29c
  }
Packit 18d29c
Packit 18d29c
  // TODO: Trim out _unittest suffix?  Perhaps it is better to have
Packit 18d29c
  // the extra control and just leave it there.
Packit 18d29c
Packit 18d29c
  // find target in vector of modules, replace site_flag_value with
Packit 18d29c
  // a module-specific verbose level, if any.
Packit 18d29c
  for (const VModuleInfo* info = vmodule_list;
Packit 18d29c
       info != NULL; info = info->next) {
Packit 18d29c
    if (SafeFNMatch_(info->module_pattern.c_str(), info->module_pattern.size(),
Packit 18d29c
                     base, base_length)) {
Packit 18d29c
      site_flag_value = &info->vlog_level;
Packit 18d29c
        // value at info->vlog_level is now what controls
Packit 18d29c
        // the VLOG at the caller site forever
Packit 18d29c
      break;
Packit 18d29c
    }
Packit 18d29c
  }
Packit 18d29c
Packit 18d29c
  // Cache the vlog value pointer if --vmodule flag has been parsed.
Packit 18d29c
  ANNOTATE_BENIGN_RACE(site_flag,
Packit 18d29c
                       "*site_flag may be written by several threads,"
Packit 18d29c
                       " but the value will be the same");
Packit 18d29c
  if (read_vmodule_flag) *site_flag = site_flag_value;
Packit 18d29c
Packit 18d29c
  // restore the errno in case something recoverable went wrong during
Packit 18d29c
  // the initialization of the VLOG mechanism (see above note "protect the..")
Packit 18d29c
  errno = old_errno;
Packit 18d29c
  return *site_flag_value >= verbose_level;
Packit 18d29c
}
Packit 18d29c
Packit 18d29c
_END_GOOGLE_NAMESPACE_