LSST Applications g070148d5b3+33e5256705,g0d53e28543+25c8b88941,g0da5cf3356+2dd1178308,g1081da9e2a+62d12e78cb,g17e5ecfddb+7e422d6136,g1c76d35bf8+ede3a706f7,g295839609d+225697d880,g2e2c1a68ba+cc1f6f037e,g2ffcdf413f+853cd4dcde,g38293774b4+62d12e78cb,g3b44f30a73+d953f1ac34,g48ccf36440+885b902d19,g4b2f1765b6+7dedbde6d2,g5320a0a9f6+0c5d6105b6,g56b687f8c9+ede3a706f7,g5c4744a4d9+ef6ac23297,g5ffd174ac0+0c5d6105b6,g6075d09f38+66af417445,g667d525e37+2ced63db88,g670421136f+2ced63db88,g71f27ac40c+2ced63db88,g774830318a+463cbe8d1f,g7876bc68e5+1d137996f1,g7985c39107+62d12e78cb,g7fdac2220c+0fd8241c05,g96f01af41f+368e6903a7,g9ca82378b8+2ced63db88,g9d27549199+ef6ac23297,gabe93b2c52+e3573e3735,gb065e2a02a+3dfbe639da,gbc3249ced9+0c5d6105b6,gbec6a3398f+0c5d6105b6,gc9534b9d65+35b9f25267,gd01420fc67+0c5d6105b6,geee7ff78d7+a14128c129,gf63283c776+ede3a706f7,gfed783d017+0c5d6105b6,w.2022.47
LSST Data Management Base Package
Loading...
Searching...
No Matches
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 <mutex>
35#include <pthread.h>
36#include <stdexcept>
37#include <stdio.h>
38#include <stdlib.h>
39#include <vector>
40
41// Third-party headers
42#include <log4cxx/basicconfigurator.h>
43#include <log4cxx/consoleappender.h>
44#include <log4cxx/helpers/bytearrayinputstream.h>
45#include <log4cxx/patternlayout.h>
46#include <log4cxx/propertyconfigurator.h>
47#include <log4cxx/xml/domconfigurator.h>
48
49// Local headers
50#include "lsst/log/Log.h"
51#include "lwpID.h"
52
53
54// Max message length for varargs/printf style logging
55#define MAX_LOG_MSG_LEN 1024
56
57namespace {
58
59// name of the env. variable pointing to logging config file
60const char configEnv[] = "LSST_LOG_CONFIG";
61
62// dafault message layout pattern
63const char layoutPattern[] = "%c %p: %m%n";
64
65/*
66 * Configure LOG4CXX from file, file must exist. If file extension is .xml
67 * then DOMConfigurator is used, otherwise PropertyConfigurator is called.
68 *
69 * If file parsing fails then error messages are printed to standard error,
70 * but execution continues. LOG4CXX will likely stay un-configured in this
71 * case.
72 */
73void configFromFile(std::string const& filename) {
74 // find position of extension
75 size_t dotpos = filename.find_last_of(".");
76 if (dotpos != std::string::npos && filename.compare(dotpos, std::string::npos, ".xml") == 0) {
77 log4cxx::xml::DOMConfigurator::configure(filename);
78 } else {
79 log4cxx::PropertyConfigurator::configure(filename);
80 }
81}
82
83/*
84 * Default configuration.
85 *
86 * If LSST_LOG_CONFIG envvar is defined and points to existing file then
87 * use that file to configure (can be either XML or Properties file).
88 * Otherwise use pre-defined configuration - add console appender to root
89 * logger using pattern layout with the above pattern, level set to INFO.
90 *
91 * IF LOG4CXX was initialized already and you want to reset it then call
92 * `log4cxx::BasicConfigurator::resetConfiguration()` first.
93 */
94void defaultConfig() {
95 // if LSST_LOG_CONFIG is set then use that file
96 if (const char* env = getenv(::configEnv)) {
97 if (env[0] and access(env, R_OK) == 0) {
98 configFromFile(env);
99 return;
100 }
101 }
102
103 // use pre-defined configuration
104 log4cxx::LogString pattern(layoutPattern);
105 log4cxx::LayoutPtr layout(new log4cxx::PatternLayout(pattern));
106 log4cxx::AppenderPtr appender(new log4cxx::ConsoleAppender(layout));
107 auto root = log4cxx::Logger::getRootLogger();
108 root->addAppender(appender);
109 root->setLevel(log4cxx::Level::getInfo());
110}
111
112// Protects concurrent configuration
113std::mutex configMutex;
114
115// global initialization flag (protected by configMutex)
116bool initialized = false;
117
118/*
119 * This method is called exactly once to initialize LOG4CXX configuration.
120 * If `initialized` is set to true then default configuration is skipped.
121 */
122log4cxx::LoggerPtr log4cxxInit() {
123
124 std::lock_guard<std::mutex> lock(configMutex);
125 if (!initialized) {
126 initialized = true;
127 // do default configuration if no one done any configuration yet
128 ::defaultConfig();
129 }
130
131 // returns root logger to be used as default logger
132 return log4cxx::Logger::getRootLogger();
133}
134
135// List of the MDC initialization functions
136std::vector<std::function<void()>> mdcInitFunctions;
137std::mutex mdcInitMutex;
138
139// more efficient alternative to pthread_once
140struct PthreadKey {
141 PthreadKey() {
142 // we don't need destructor for a key
143 pthread_key_create(&key, nullptr);
144 }
145 pthread_key_t key;
146} pthreadKey;
147
148} // namespace
149
150
151namespace lsst {
152namespace log {
153
154
155// Log class
156
160log4cxx::LoggerPtr const& Log::_defaultLogger() {
161
162 // initialize on the first call (skips initialization if someone else did that)
163 static log4cxx::LoggerPtr _default(::log4cxxInit());
164
165 return _default;
166}
167
178 std::lock_guard<std::mutex> lock(::configMutex);
179
180 // Make sure other threads know that default configuration is not needed
181 ::initialized = true;
182
183 // This removes all defined appenders, resets level to DEBUG,
184 // existing loggers are not deleted, only reset.
185 log4cxx::BasicConfigurator::resetConfiguration();
186
187 // Do default configuration (only if not configured already?)
188 ::defaultConfig();
189}
190
201void Log::configure(std::string const& filename) {
202 std::lock_guard<std::mutex> lock(::configMutex);
203
204 // Make sure other threads know that default configuration is not needed
205 ::initialized = true;
206
207 // This removes all defined appenders, resets level to DEBUG,
208 // existing loggers are not deleted, only reset.
209 log4cxx::BasicConfigurator::resetConfiguration();
210
211 ::configFromFile(filename);
212}
213
220void Log::configure_prop(std::string const& properties) {
221 std::lock_guard<std::mutex> lock(::configMutex);
222
223 // Make sure other threads know that default configuration is not needed
224 ::initialized = true;
225
226 // This removes all defined appenders, resets level to DEBUG,
227 // existing loggers are not deleted, only reset.
228 log4cxx::BasicConfigurator::resetConfiguration();
229
230 std::vector<unsigned char> data(properties.begin(), properties.end());
231 log4cxx::helpers::InputStreamPtr inStream(new log4cxx::helpers::ByteArrayInputStream(data));
232 log4cxx::helpers::Properties prop;
233 prop.load(inStream);
234 log4cxx::PropertyConfigurator::configure(prop);
235}
236
241 std::string name = _logger->getName();
242 if (name == "root") {
243 name.clear();
244 }
245 return name;
246}
247
256Log Log::getLogger(std::string const& loggername) {
257 if (loggername.empty()){
258 return getDefaultLogger();
259 } else {
260 return Log(log4cxx::Logger::getLogger(loggername));
261 }
262}
263
274std::string Log::MDC(std::string const& key, std::string const& value) {
275 // put() does not remove existing mapping, to make it less confusing
276 // for clients which expect that MDC() always overwrites existing mapping
277 // we explicitly remove it first if it exists.
278 std::string const oldValue = log4cxx::MDC::get(key);
279 log4cxx::MDC::remove(key);
280 log4cxx::MDC::put(key, value);
281 return oldValue;
282}
283
288void Log::MDCRemove(std::string const& key) {
289 log4cxx::MDC::remove(key);
290}
291
292int Log::MDCRegisterInit(std::function<void()> function) {
293
294 std::lock_guard<std::mutex> lock(mdcInitMutex);
295
296 // logMsg may have been called already in this thread, to make sure that
297 // this function is executed in this thread call it explicitly
298 function();
299
300 // store function for later use
301 ::mdcInitFunctions.push_back(std::move(function));
302
303 // return arbitrary number
304 return 1;
305}
306
311void Log::setLevel(int level) {
312 _logger->setLevel(log4cxx::Level::toLevel(level));
313}
314
318int Log::getLevel() const {
319 log4cxx::LevelPtr level = _logger->getLevel();
320 int levelno = -1;
321 if (level != NULL) {
322 levelno = level->toInt();
323 }
324 return levelno;
325}
326
331 log4cxx::LevelPtr level = _logger->getEffectiveLevel();
332 int levelno = -1;
333 if (level != NULL) {
334 levelno = level->toInt();
335 }
336 return levelno;
337}
338
345bool Log::isEnabledFor(int level) const {
346 if (_logger->isEnabledFor(log4cxx::Level::toLevel(level))) {
347 return true;
348 } else {
349 return false;
350 }
351}
352
366Log Log::getChild(std::string const& suffix) const {
367 // strip leading dots and spaces from suffix
368 auto pos = suffix.find_first_not_of(" .");
369 if (pos == std::string::npos) {
370 // empty, just return myself
371 return *this;
372 }
374 if (name.empty()) {
375 name = suffix.substr(pos);
376 } else {
377 name += '.';
378 name += suffix.substr(pos);
379 }
380 return getLogger(name);
381}
382
386void Log::log(log4cxx::LevelPtr level,
387 log4cxx::spi::LocationInfo const& location,
388 char const* fmt,
389 ...
390 ) {
391 va_list args;
392 va_start(args, fmt);
393 char msg[MAX_LOG_MSG_LEN];
394 vsnprintf(msg, MAX_LOG_MSG_LEN, fmt, args);
395 logMsg(level, location, msg);
396}
397
400void Log::logMsg(log4cxx::LevelPtr level,
401 log4cxx::spi::LocationInfo const& location,
402 std::string const& msg
403 ) {
404
405 // do one-time per-thread initialization, this was implemented
406 // with thread_local initially but clang on OS X did not support it
407 void *ptr = pthread_getspecific(::pthreadKey.key);
408 if (ptr == nullptr) {
409
410 // use pointer value as a flag, don't care where it points to
411 ptr = static_cast<void*>(&::pthreadKey);
412 pthread_setspecific(::pthreadKey.key, ptr);
413
414 std::lock_guard<std::mutex> lock(mdcInitMutex);
415 // call all functions in the MDC init list
416 for (auto& fun: mdcInitFunctions) {
417 fun();
418 }
419 }
420
421 // forward everything to logger
422 _logger->forcedLog(level, msg, location);
423}
424
425unsigned lwpID() {
426 return detail::lwpID();
427}
428
429}} // namespace lsst::log
table::Key< std::string > name
Definition: Amplifier.cc:116
char * data
Definition: BaseRecord.cc:61
LSST DM logging module built on log4cxx.
uint64_t * ptr
Definition: RangeSet.cc:88
T begin(T... args)
This static class includes a variety of methods for interacting with the the logging module.
Definition: Log.h:724
static Log getDefaultLogger()
Return default logger instance, same as default constructor.
Definition: Log.h:766
static Log getLogger(Log const &logger)
Definition: Log.h:772
static void MDCRemove(std::string const &key)
Remove the value associated with KEY within the MDC.
Definition: Log.cc:288
int getLevel() const
Retrieve the logging threshold.
Definition: Log.cc:318
bool isEnabledFor(int level) const
Return whether the logging threshold of the logger is less than or equal to LEVEL.
Definition: Log.cc:345
void logMsg(log4cxx::LevelPtr level, log4cxx::spi::LocationInfo const &location, std::string const &msg)
Method used by LOGS_INFO and similar macros to process a log message.
Definition: Log.cc:400
Log getChild(std::string const &suffix) const
Return a logger which is a descendant to this logger.
Definition: Log.cc:366
static void configure_prop(std::string const &properties)
Configures log4cxx using a string containing the list of properties, equivalent to configuring from a...
Definition: Log.cc:220
void setLevel(int level)
Set the logging threshold to LEVEL.
Definition: Log.cc:311
static void configure()
Explicitly configures log4cxx and initializes logging system.
Definition: Log.cc:177
static std::string MDC(std::string const &key, std::string const &value)
Places a KEY/VALUE pair in the Mapped Diagnostic Context (MDC) for the current thread.
Definition: Log.cc:274
static int MDCRegisterInit(std::function< void()> function)
Definition: Log.cc:292
void log(log4cxx::LevelPtr level, log4cxx::spi::LocationInfo const &location, char const *fmt,...)
Method used by LOG_INFO and similar macros to process a log message with variable arguments along wit...
Definition: Log.cc:386
std::string getName() const
Get the logger name associated with the Log object.
Definition: Log.cc:240
int getEffectiveLevel() const
Retrieve the effective logging threshold.
Definition: Log.cc:330
T compare(T... args)
T empty(T... args)
T end(T... args)
T find_first_not_of(T... args)
T find_last_of(T... args)
T move(T... args)
unsigned lwpID()
Definition: lwpID.cc:40
unsigned lwpID()
Function which returns LWP ID on platforms which support it.
Definition: Log.cc:425
#define MAX_LOG_MSG_LEN
Definition: Log.cc:55
T substr(T... args)