LSSTApplications  10.0+286,10.0+36,10.0+46,10.0-2-g4f67435,10.1+152,10.1+37,11.0,11.0+1,11.0-1-g47edd16,11.0-1-g60db491,11.0-1-g7418c06,11.0-2-g04d2804,11.0-2-g68503cd,11.0-2-g818369d,11.0-2-gb8b8ce7
LSSTDataManagementBasePackage
Log.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*-
2 /*
3  * LSST Data Management System
4  * Copyright 2013-2014 LSST Corporation.
5  *
6  * This product includes software developed by the
7  * LSST Project (http://www.lsst.org/).
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the LSST License Statement and
20  * the GNU General Public License along with this program. If not,
21  * see <http://www.lsstcorp.org/LegalNotices/>.
22  */
23 
33 // System headers
34 #include <stdexcept>
35 #include <stdio.h>
36 #include <stdlib.h>
37 
38 // Third-party headers
39 #include <log4cxx/basicconfigurator.h>
40 #include <log4cxx/consoleappender.h>
41 #include <log4cxx/helpers/bytearrayinputstream.h>
42 #include <log4cxx/logmanager.h>
43 #include <log4cxx/propertyconfigurator.h>
44 #include <log4cxx/simplelayout.h>
45 #include <log4cxx/xml/domconfigurator.h>
46 
47 // Local headers
48 #include "lsst/log/Log.h"
49 
50 
51 // Max message length for varargs/printf style logging
52 #define MAX_LOG_MSG_LEN 1024
53 
54 
55 namespace {
56 
57 // name of the env. variable pointing to logging config file
58 const char configEnv[] = "LSST_LOG_CONFIG";
59 
60 /*
61  * Logging is configured at global initialization time (though everybody knows this is evil
62  * thing to do). What we want to do:
63  * - Let user re-configure later with LOG_CONFIG(filename) - this means that we do not
64  * do anything fancy here like initializing from some other file
65  * - if LSST_LOG_CONFIG is set to existing file name then we want to configure from
66  * that file but only if user does not call LOG_CONFIG(filename)
67  * - this means that we should leave it to log4cxx to default-configure using that file
68  * name (meaning that we want to set LOG4CXX_CONFIGURATION)
69  * - otherwise do basic configuration only
70  */
71 bool init() {
72  if (const char* env = getenv(::configEnv)) {
73  // check that file actually exists
74  if (env[0] and access(env, R_OK) == 0) {
75  // prepare for default initialization in log4cxx if
76  // user does not do LOG_CONFIG(...)
77  ::setenv("LOG4CXX_CONFIGURATION", env, 1);
78  return true;
79  }
80  }
81  // do basic configuration only
84 
85  return true;
86 }
87 
88 bool initialized = init();
89 
90 }
91 
92 
93 namespace lsst {
94 namespace log {
95 
96 // Log class
97 
100 log4cxx::LoggerPtr Log::defaultLogger = log4cxx::Logger::getRootLogger();
101 
104 void Log::initLog() {
105  // Default logger initially set to root logger
106  defaultLogger = log4cxx::Logger::getRootLogger();
107 }
108 
120  // TODO: does resetConfiguration() remove existing appenders?
121  log4cxx::BasicConfigurator::resetConfiguration();
122 
123  // if LSST_LOG_CONFIG is set then use that file
124  if (const char* env = getenv(::configEnv)) {
125  if (env[0] and access(env, R_OK) == 0) {
126  configure(env);
127  return;
128  }
129  }
130 
131  // Do basic configuration (only if not configured already?)
132  log4cxx::LoggerPtr rootLogger = log4cxx::Logger::getRootLogger();
133  if (rootLogger->getAllAppenders().size() == 0) {
135  }
136  initLog();
137 }
138 
139 std::string getFileExtension(std::string const& filename) {
140  size_t dotpos = filename.find_last_of(".");
141  if (dotpos == std::string::npos) {
142  return "";
143  }
144  return filename.substr(dotpos, filename.size() - dotpos);
145 }
146 
156 void Log::configure(std::string const& filename) {
157  // TODO: does resetConfiguration() remove existing appenders?
158  log4cxx::BasicConfigurator::resetConfiguration();
159  if (getFileExtension(filename).compare(".xml") == 0) {
161  } else {
163  }
164  initLog();
165 }
166 
173 void Log::configure_prop(std::string const& properties) {
174  std::vector<unsigned char> data(properties.begin(), properties.end());
175  log4cxx::helpers::InputStreamPtr inStream(new log4cxx::helpers::ByteArrayInputStream(data));
176  log4cxx::helpers::Properties prop;
177  prop.load(inStream);
179  initLog();
180 }
181 
186  std::string name = defaultLogger->getName();
187  if (name == "root") {
188  name.clear();
189  }
190  return name;
191 }
192 
199 log4cxx::LoggerPtr Log::getLogger(log4cxx::LoggerPtr logger) {
200  return logger;
201 }
202 
209 log4cxx::LoggerPtr Log::getLogger(std::string const& loggername) {
210  if (loggername.empty()){
211  return defaultLogger;
212  } else {
213  return log4cxx::Logger::getLogger(loggername);
214  }
215 }
216 
221 void Log::pushContext(std::string const& name) {
222  // can't handle empty names
223  if (name.empty()) {
224  throw std::invalid_argument("lsst::log::Log::pushContext(): "
225  "empty context name is not allowed");
226  }
227  // we do not allow multi-level context (logger1.logger2)
228  if (name.find('.') != std::string::npos) {
229  throw std::invalid_argument("lsst::log::Log::pushContext(): "
230  "multi-level contexts are not allowed: " + name);
231  }
232 
233  // Construct new default logger name
234  std::string newName = defaultLogger->getName();
235  if (newName == "root") {
236  newName = name;
237  } else {
238  newName += ".";
239  newName += name;
240  }
241  // Update defaultLogger
242  defaultLogger = log4cxx::Logger::getLogger(newName);
243 }
244 
249  // switch to parent logger, this assumes that loggers are not
250  // re-parented between calls to push and pop
251  log4cxx::LoggerPtr parent = defaultLogger->getParent();
252  // root logger does not have parent, stay at root instead
253  if (parent) {
254  defaultLogger = parent;
255  }
256 }
257 
266 void Log::MDC(std::string const& key, std::string const& value) {
267  log4cxx::MDC::put(key, value);
268 }
269 
274 void Log::MDCRemove(std::string const& key) {
275  log4cxx::MDC::remove(key);
276 }
277 
283 void Log::setLevel(log4cxx::LoggerPtr logger, int level) {
284  logger->setLevel(log4cxx::Level::toLevel(level));
285 }
286 
292 void Log::setLevel(std::string const& loggername, int level) {
293  setLevel(getLogger(loggername), level);
294 }
295 
301 int Log::getLevel(log4cxx::LoggerPtr logger) {
302  log4cxx::LevelPtr level = logger->getLevel();
303  int levelno = -1;
304  if (level != NULL) {
305  levelno = level->toInt();
306  }
307  return levelno;
308 }
309 
315 int Log::getLevel(std::string const& loggername) {
316  return getLevel(getLogger(loggername));
317 }
318 
326 bool Log::isEnabledFor(log4cxx::LoggerPtr logger, int level) {
327  if (logger->isEnabledFor(log4cxx::Level::toLevel(level))) {
328  return true;
329  } else {
330  return false;
331  }
332 }
333 
341 bool Log::isEnabledFor(std::string const& loggername, int level) {
342  return isEnabledFor(getLogger(loggername), level);
343 }
344 
345 void Log::vlog(log4cxx::LoggerPtr logger,
346  log4cxx::LevelPtr level,
347  std::string const& filename,
348  std::string const& funcname,
349  unsigned int lineno,
350  char const* fmt,
351  va_list args
352  ) {
353  char msg[MAX_LOG_MSG_LEN];
354  vsnprintf(msg, MAX_LOG_MSG_LEN, fmt, args);
355  logger->forcedLog(level, msg, log4cxx::spi::LocationInfo(filename.c_str(),
356  funcname.c_str(),
357  lineno));
358 }
359 
360 void Log::log(std::string const& loggername,
361  log4cxx::LevelPtr level,
362  std::string const& filename,
363  std::string const& funcname,
364  unsigned int lineno,
365  char const* fmt,
366  ...
367  ) {
368  va_list args;
369  va_start(args, fmt);
370  vlog(getLogger(loggername), level, filename, funcname, lineno, fmt, args);
371 }
372 
376 void Log::log(log4cxx::LoggerPtr logger,
377  log4cxx::LevelPtr level,
378  std::string const& filename,
379  std::string const& funcname,
380  unsigned int lineno,
381  char const* fmt,
382  ...
383  ) {
384  va_list args;
385  va_start(args, fmt);
386  vlog(logger, level, filename, funcname, lineno, fmt, args);
387 }
388 
389 }} // namespace lsst::log
static log4cxx::LoggerPtr defaultLogger
Definition: Log.h:491
table::Key< std::string > name
Definition: ApCorrMap.cc:71
static void configure(void)
Definition: Log.cc:119
def configure
Definition: log.py:42
def log
Definition: log.py:85
static log4cxx::LoggerPtr getLogger(log4cxx::LoggerPtr logger)
Definition: Log.cc:199
static void pushContext(std::string const &name)
Definition: Log.cc:221
static std::string getDefaultLoggerName(void)
Definition: Log.cc:185
#define MAX_LOG_MSG_LEN
Definition: Log.cc:52
static void initLog(void)
Definition: Log.cc:104
static void vlog(log4cxx::LoggerPtr logger, log4cxx::LevelPtr level, std::string const &filename, std::string const &funcname, unsigned int lineno, char const *fmt, va_list args)
Definition: Log.cc:345
static int getLevel(log4cxx::LoggerPtr logger)
Definition: Log.cc:301
static void MDCRemove(std::string const &key)
Definition: Log.cc:274
static void MDC(std::string const &key, std::string const &value)
Definition: Log.cc:266
static bool isEnabledFor(log4cxx::LoggerPtr logger, int level)
Definition: Log.cc:326
static void popContext(void)
Definition: Log.cc:248
static void configure_prop(std::string const &properties)
Definition: Log.cc:173
static void log(std::string const &loggername, log4cxx::LevelPtr level, std::string const &filename, std::string const &funcname, unsigned int lineno, char const *fmt,...)
Definition: Log.cc:360
static void setLevel(log4cxx::LoggerPtr logger, int level)
Definition: Log.cc:283
std::string getFileExtension(std::string const &filename)
Definition: Log.cc:139