1 /*
2  * Category.cpp
3  *
4  * Copyright 2000, LifeLine Networks BV (www.lifeline.nl). All rights reserved.
5  * Copyright 2000, Bastiaan Bakker. All rights reserved.
6  *
7  * See the COPYING file for the terms of usage and distribution.
8  */
9 
10 #include "PortabilityImpl.hh"
11 
12 #ifdef LOG4CPP_HAVE_UNISTD_H
13 #    include <unistd.h>
14 #endif
15 
16 #include <log4cpp/Category.hh>
17 #include <log4cpp/HierarchyMaintainer.hh>
18 #include <log4cpp/NDC.hh>
19 #include "StringUtil.hh"
20 
21 namespace log4cpp {
22 
getRoot()23     Category& Category::getRoot() {
24         return getInstance("");
25     }
26 
setRootPriority(Priority::Value priority)27     void Category::setRootPriority(Priority::Value priority) {
28         getRoot().setPriority(priority);
29     }
30 
getRootPriority()31     Priority::Value Category::getRootPriority() throw() {
32         return getRoot().getPriority();
33     }
34 
getInstance(const std::string & name)35     Category& Category::getInstance(const std::string& name) {
36         return HierarchyMaintainer::getDefaultMaintainer().getInstance(name);
37     }
38 
exists(const std::string & name)39     Category* Category::exists(const std::string& name) {
40         return HierarchyMaintainer::getDefaultMaintainer().getExistingInstance(name);
41     }
42 
getCurrentCategories()43     std::vector<Category*>* Category::getCurrentCategories() {
44         return HierarchyMaintainer::getDefaultMaintainer().
45             getCurrentCategories();
46     }
47 
shutdown()48     void Category::shutdown() {
49         HierarchyMaintainer::getDefaultMaintainer().shutdown();
50     }
51 
shutdownForced()52     void Category::shutdownForced() {
53         HierarchyMaintainer::getDefaultMaintainer().shutdown();
54 		Appender::_deleteAllAppenders();
55     }
56 
57 
Category(const std::string & name,Category * parent,Priority::Value priority)58     Category::Category(const std::string& name, Category* parent, Priority::Value priority) :
59         _name(name),
60         _parent(parent),
61         _priority(priority),
62         _isAdditive(true) {
63     }
64 
~Category()65     Category::~Category() {
66         removeAllAppenders();
67     }
68 
getName() const69     const std::string& Category::getName() const throw() {
70         return _name;
71     }
72 
getPriority() const73     Priority::Value Category::getPriority() const throw() {
74         return _priority;
75     }
76 
setPriority(Priority::Value priority)77     void Category::setPriority(Priority::Value priority) {
78         if ((priority < Priority::NOTSET) || (getParent() != NULL)) {
79             _priority = priority;
80         } else {
81             /* caller tried to set NOTSET priority to root Category.
82                Bad caller!
83             */
84             throw std::invalid_argument("cannot set priority NOTSET on Root Category");
85         }
86     }
87 
getChainedPriority() const88     Priority::Value Category::getChainedPriority() const throw() {
89         // REQUIRE(rootCategory->getPriority() != Priority::NOTSET)
90 
91         const Category* c = this;
92         while(c->getPriority() >= Priority::NOTSET) {
93             c = c->getParent();
94         }
95 
96         return c->getPriority();
97     }
98 
addAppender(Appender * appender)99     void Category::addAppender(Appender* appender) {
100         if (appender) {
101             threading::ScopedLock lock(_appenderSetMutex);
102             {
103                 AppenderSet::iterator i = _appender.find(appender);
104                 if (_appender.end() == i) {
105                     // not found
106                     _appender.insert(appender);
107                     _ownsAppender[appender] = true;
108                 }
109             }
110         } else {
111             throw std::invalid_argument("NULL appender");
112         }
113     }
114 
addAppender(Appender & appender)115     void Category::addAppender(Appender& appender) {
116         threading::ScopedLock lock(_appenderSetMutex);
117         {
118             AppenderSet::iterator i = _appender.find(&appender);
119             if (_appender.end() == i) {
120                 _appender.insert(&appender);
121                 _ownsAppender[&appender] = false;
122             }
123         }
124     }
125 
getAppender() const126     Appender* Category::getAppender() const {
127         threading::ScopedLock lock(_appenderSetMutex);
128         {
129             AppenderSet::const_iterator i = _appender.begin();
130             return (_appender.end() == i) ? NULL : *i;
131         }
132     }
133 
getAppender(const std::string & name) const134     Appender* Category::getAppender(const std::string& name) const {
135         threading::ScopedLock lock(_appenderSetMutex);
136         {
137             AppenderSet::const_iterator i = _appender.begin();
138             if (_appender.end() != i) {
139                 // found
140                 return((*i)->getAppender(name));
141             }
142             else {
143                 return(NULL);
144             }
145         }
146     }
147 
getAllAppenders() const148     AppenderSet Category::getAllAppenders() const {
149         threading::ScopedLock lock(_appenderSetMutex);
150         {
151             return _appender;
152         }
153     }
154 
removeAllAppenders()155     void Category::removeAllAppenders() {
156         threading::ScopedLock lock(_appenderSetMutex);
157         {
158             for (AppenderSet::iterator i = _appender.begin();
159                  i != _appender.end(); i++) {
160                 // found
161                 OwnsAppenderMap::iterator i2;
162                 if (ownsAppender(*i, i2)) {
163                     delete (*i);
164                 }
165             }
166 
167             _ownsAppender.clear();
168             _appender.clear();
169         }
170     }
171 
removeAppender(Appender * appender)172     void Category::removeAppender(Appender* appender) {
173         threading::ScopedLock lock(_appenderSetMutex);
174         {
175             AppenderSet::iterator i = _appender.find(appender);
176             if (_appender.end() != i) {
177                 OwnsAppenderMap::iterator i2;
178                 if (ownsAppender(*i, i2)) {
179                     _ownsAppender.erase(i2);
180                     delete (*i);
181                 }
182                 _appender.erase(i);
183             } else {
184                 // appender not found
185             }
186         }
187     }
188 
ownsAppender(Appender * appender) const189     bool Category::ownsAppender(Appender* appender) const throw() {
190         bool owned = false;
191 
192         threading::ScopedLock lock(_appenderSetMutex);
193         {
194             if (NULL != appender) {
195                 OwnsAppenderMap::const_iterator i =
196                     _ownsAppender.find(appender);
197                 if (_ownsAppender.end() != i) {
198                     owned = (*i).second;
199                 }
200             }
201         }
202 
203         return owned;
204     }
205 
206     /* assume lock is held */
ownsAppender(Appender * appender,Category::OwnsAppenderMap::iterator & i2)207     bool Category::ownsAppender(Appender* appender,
208                                 Category::OwnsAppenderMap::iterator& i2) throw() {
209         bool owned = false;
210 
211         if (NULL != appender) {
212             OwnsAppenderMap::iterator i = _ownsAppender.find(appender);
213             if (_ownsAppender.end() != i) {
214                 owned = (*i).second;
215                 if (owned) {
216                     i2 = i;
217                 }
218             }
219         }
220 
221         return owned;
222     }
223 
callAppenders(const LoggingEvent & event)224     void Category::callAppenders(const LoggingEvent& event) throw() {
225         threading::ScopedLock lock(_appenderSetMutex);
226         {
227             if (!_appender.empty()) {
228                 for(AppenderSet::const_iterator i = _appender.begin();
229                     i != _appender.end(); i++) {
230                     (*i)->doAppend(event);
231                 }
232             }
233         }
234         if (getAdditivity() && (getParent() != NULL)) {
235             getParent()->callAppenders(event);
236         }
237     }
238 
setAdditivity(bool additivity)239     void Category::setAdditivity(bool additivity) {
240         _isAdditive = additivity;
241     }
242 
getAdditivity() const243     bool Category::getAdditivity() const throw() {
244         return _isAdditive;
245     }
246 
getParent()247     Category* Category::getParent() throw() {
248         return _parent;
249     }
250 
getParent() const251     const Category* Category::getParent() const throw() {
252         return _parent;
253     }
254 
_logUnconditionally(Priority::Value priority,const char * format,va_list arguments)255     void Category::_logUnconditionally(Priority::Value priority,
256                                        const char* format,
257                                        va_list arguments) throw() {
258         _logUnconditionally2(priority, StringUtil::vform(format, arguments));
259     }
260 
_logUnconditionally2(Priority::Value priority,const std::string & message)261     void Category::_logUnconditionally2(Priority::Value priority,
262                                         const std::string& message) throw() {
263         LoggingEvent event(getName(), message, NDC::get(), priority);
264         callAppenders(event);
265     }
266 
isPriorityEnabled(Priority::Value priority) const267     bool Category::isPriorityEnabled(Priority::Value priority) const throw() {
268         return(getChainedPriority() >= priority);
269     }
270 
log(Priority::Value priority,const char * stringFormat,...)271     void Category::log(Priority::Value priority,
272                        const char* stringFormat, ...) throw() {
273         if (isPriorityEnabled(priority)) {
274             va_list va;
275             va_start(va, stringFormat);
276             _logUnconditionally(priority, stringFormat, va);
277             va_end(va);
278         }
279     }
280 
log(Priority::Value priority,const std::string & message)281     void Category::log(Priority::Value priority,
282                        const std::string& message) throw() {
283         if (isPriorityEnabled(priority))
284             _logUnconditionally2(priority, message);
285     }
286 
logva(Priority::Value priority,const char * stringFormat,va_list va)287     void Category::logva(Priority::Value priority,
288                          const char* stringFormat,
289                          va_list va) throw() {
290         if (isPriorityEnabled(priority)) {
291             _logUnconditionally(priority, stringFormat, va);
292         }
293     }
294 
debug(const char * stringFormat,...)295     void Category::debug(const char* stringFormat, ...) throw() {
296         if (isPriorityEnabled(Priority::DEBUG)) {
297             va_list va;
298             va_start(va,stringFormat);
299             _logUnconditionally(Priority::DEBUG, stringFormat, va);
300             va_end(va);
301         }
302     }
303 
debug(const std::string & message)304     void Category::debug(const std::string& message) throw() {
305         if (isPriorityEnabled(Priority::DEBUG))
306             _logUnconditionally2(Priority::DEBUG, message);
307     }
308 
info(const char * stringFormat,...)309     void Category::info(const char* stringFormat, ...) throw() {
310         if (isPriorityEnabled(Priority::INFO)) {
311             va_list va;
312             va_start(va,stringFormat);
313             _logUnconditionally(Priority::INFO, stringFormat, va);
314             va_end(va);
315         }
316     }
317 
info(const std::string & message)318     void Category::info(const std::string& message) throw() {
319         if (isPriorityEnabled(Priority::INFO))
320             _logUnconditionally2(Priority::INFO, message);
321     }
322 
notice(const char * stringFormat,...)323     void Category::notice(const char* stringFormat, ...) throw() {
324         if (isPriorityEnabled(Priority::NOTICE)) {
325             va_list va;
326             va_start(va,stringFormat);
327             _logUnconditionally(Priority::NOTICE, stringFormat, va);
328             va_end(va);
329         }
330     }
331 
notice(const std::string & message)332     void Category::notice(const std::string& message) throw() {
333         if (isPriorityEnabled(Priority::NOTICE))
334             _logUnconditionally2(Priority::NOTICE, message);
335     }
336 
warn(const char * stringFormat,...)337     void Category::warn(const char* stringFormat, ...) throw() {
338         if (isPriorityEnabled(Priority::WARN)) {
339             va_list va;
340             va_start(va,stringFormat);
341             _logUnconditionally(Priority::WARN, stringFormat, va);
342             va_end(va);
343         }
344     }
345 
warn(const std::string & message)346     void Category::warn(const std::string& message) throw() {
347         if (isPriorityEnabled(Priority::WARN))
348             _logUnconditionally2(Priority::WARN, message);
349     }
350 
error(const char * stringFormat,...)351     void Category::error(const char* stringFormat, ...) throw() {
352         if (isPriorityEnabled(Priority::ERROR)) {
353             va_list va;
354             va_start(va,stringFormat);
355                        _logUnconditionally(Priority::ERROR, stringFormat, va);
356             va_end(va);
357         }
358     }
359 
error(const std::string & message)360     void Category::error(const std::string& message) throw() {
361         if (isPriorityEnabled(Priority::ERROR))
362             _logUnconditionally2(Priority::ERROR, message);
363     }
364 
crit(const char * stringFormat,...)365     void Category::crit(const char* stringFormat, ...) throw() {
366         if (isPriorityEnabled(Priority::CRIT)) {
367             va_list va;
368             va_start(va,stringFormat);
369             _logUnconditionally(Priority::CRIT, stringFormat, va);
370             va_end(va);
371         }
372     }
373 
crit(const std::string & message)374     void Category::crit(const std::string& message) throw() {
375         if (isPriorityEnabled(Priority::CRIT))
376             _logUnconditionally2(Priority::CRIT, message);
377     }
378 
alert(const char * stringFormat,...)379     void Category::alert(const char* stringFormat, ...) throw() {
380         if (isPriorityEnabled(Priority::ALERT)) {
381             va_list va;
382             va_start(va,stringFormat);
383             _logUnconditionally(Priority::ALERT, stringFormat, va);
384             va_end(va);
385         }
386     }
387 
alert(const std::string & message)388     void Category::alert(const std::string& message) throw() {
389         if (isPriorityEnabled(Priority::ALERT))
390             _logUnconditionally2(Priority::ALERT, message);
391     }
392 
emerg(const char * stringFormat,...)393     void Category::emerg(const char* stringFormat, ...) throw() {
394         if (isPriorityEnabled(Priority::EMERG)) {
395             va_list va;
396             va_start(va,stringFormat);
397             _logUnconditionally(Priority::EMERG, stringFormat, va);
398             va_end(va);
399         }
400     }
401 
emerg(const std::string & message)402     void Category::emerg(const std::string& message) throw() {
403         if (isPriorityEnabled(Priority::EMERG))
404             _logUnconditionally2(Priority::EMERG, message);
405     }
406 
fatal(const char * stringFormat,...)407     void Category::fatal(const char* stringFormat, ...) throw() {
408         if (isPriorityEnabled(Priority::FATAL)) {
409             va_list va;
410             va_start(va,stringFormat);
411             _logUnconditionally(Priority::FATAL, stringFormat, va);
412             va_end(va);
413         }
414     }
415 
fatal(const std::string & message)416     void Category::fatal(const std::string& message) throw() {
417         if (isPriorityEnabled(Priority::FATAL))
418             _logUnconditionally2(Priority::FATAL, message);
419     }
420 
getStream(Priority::Value priority)421     CategoryStream Category::getStream(Priority::Value priority) {
422         return CategoryStream(*this, isPriorityEnabled(priority) ?
423                               priority : Priority::NOTSET);
424     }
425 
operator <<(Priority::Value priority)426     CategoryStream Category::operator<<(Priority::Value priority) {
427         return getStream(priority);
428     }
429 }
430 
431