OrocosComponentLibrary  2.9.0
LoggingService.cpp
1 #include "logging/LoggingService.hpp"
2 #include "logging/Category.hpp"
3 #include "ocl/Component.hpp"
4 
5 #include <boost/algorithm/string.hpp>
6 #include <log4cpp/Category.hh>
7 #include <log4cpp/Priority.hh>
8 #include <log4cpp/HierarchyMaintainer.hh>
9 
10 #include <rtt/Logger.hpp>
11 #include <typeinfo>
12 
13 using namespace RTT;
14 using namespace std;
15 
16 namespace OCL {
17 namespace logging {
18 
19 LoggingService::LoggingService(std::string name) :
20  RTT::TaskContext(name),
21  levels_prop("Levels","A PropertyBag defining the level of each category of interest."),
22  additivity_prop("Additivity","A PropertyBag defining the additivity of each category of interest."),
23  appenders_prop("Appenders","A PropertyBag defining the appenders for each category of interest."),
24  logCategories_mtd("logCategories", &LoggingService::logCategories, this)
25 {
26  this->properties()->addProperty( levels_prop );
27  this->properties()->addProperty( additivity_prop );
28  this->properties()->addProperty( appenders_prop );
29  this->provides()->addOperation( logCategories_mtd ).doc("Log category hierarchy (not realtime!)");
30 }
31 
32 LoggingService::~LoggingService()
33 {
34 }
35 
36 bool LoggingService::configureHook()
37 {
38  log(Debug) << "Configuring LoggingService" << endlog();
39 
40  // set the priority/level for each category
41 
42  PropertyBag bag = levels_prop.value(); // an empty bag is ok
43 
44  bool ok = true;
45  PropertyBag::const_iterator it;
46  for (it=bag.getProperties().begin(); it != bag.getProperties().end(); ++it)
47  {
48  Property<std::string>* category = dynamic_cast<Property<std::string>* >( *it );
49  if ( !category )
50  {
51  log(Error) << "Expected Property '"
52  << (*it)->getName() << "' to be of type string." << endlog();
53  }
54  else
55  {
56  std::string categoryName = category->getName();
57  std::string levelName = category->value();
58 
59  // "" == categoryName implies the root category.
60 
61  // \todo else if level is empty
62 
63  // log4cpp only takes upper case
64  boost::algorithm::to_upper(levelName);
65 
66  log4cpp::Priority::Value priority = log4cpp::Priority::NOTSET;
67  try
68  {
69  priority = log4cpp::Priority::getPriorityValue(levelName);
70 
71  }
72  catch (std::invalid_argument)
73  {
74  // \todo more descriptive
75  log(Error) << "Bad level name: " << levelName << endlog();
76  return false;
77  }
78 
79  log(Debug) << "Getting category '" << categoryName << "'" << endlog();
80  log4cpp::Category& category =
81  log4cpp::Category::getInstance(categoryName);
82 
83  category.setPriority(priority);
84  log(Info) << "Category '" << categoryName
85  << "' has priority '" << levelName << "'"
86  << endlog();
87  }
88  }
89 
90  // first clear all existing appenders in order to avoid double connects:
91  for(vector<string>::iterator it = active_appenders.begin(); it != active_appenders.end(); ++it) {
92  base::PortInterface* port = 0;
93  TaskContext* appender = getPeer(*it);
94  if (appender && (port = appender->ports()->getPort("LogPort")) )
95  port->disconnect();
96  }
97  if ( !active_appenders.empty() )
98  log(Warning) <<"Reconfiguring LoggingService '"<<getName() << "': I've removed all existing Appender connections and will now rebuild them."<<endlog();
99  active_appenders.clear();
100 
101  // set the additivity of each category
102 
103  bag = additivity_prop.value(); // an empty bag is ok
104 
105  for (it=bag.getProperties().begin(); it != bag.getProperties().end(); ++it)
106  {
107  Property<bool>* category = dynamic_cast<Property<bool>* >( *it );
108  if ( !category )
109  {
110  log(Error) << "Expected Property '"
111  << (*it)->getName() << "' to be of type boolean." << endlog();
112  }
113  else
114  {
115  std::string categoryName = category->getName();
116  bool additivity = category->value();
117 
118  // "" == categoryName implies the root category.
119 
120  log(Debug) << "Getting category '" << categoryName << "'" << endlog();
121  log4cpp::Category& category =
122  log4cpp::Category::getInstance(categoryName);
123 
124  category.setAdditivity(additivity);
125  log(Info) << "Category '" << categoryName
126  << "' has additivity '" << std::string(additivity ? "on":"off") << "'"
127  << endlog();
128  }
129  }
130 
131  // create a port for each appender, and associate category/appender
132 
133  bag = appenders_prop.value(); // an empty bag is ok
134 
135  ok = true;
136  for (it=bag.getProperties().begin(); it != bag.getProperties().end(); ++it)
137  {
138  Property<std::string>* association = dynamic_cast<Property<std::string>* >( *it );
139  if ( !association )
140  {
141  log(Error) << "Expected Property '"
142  << (*it)->getName() << "' to be of type string." << endlog();
143  }
144  // \todo else if name or level are empty
145  else
146  {
147  std::string categoryName = association->getName();
148  std::string appenderName = association->value();
149 
150  // find category
151  log4cpp::Category* p = log4cpp::HierarchyMaintainer::getDefaultMaintainer().getExistingInstance(categoryName);
152  OCL::logging::Category* category =
153  dynamic_cast<OCL::logging::Category*>(p);
154  if (0 == category)
155  {
156  if (0 != p)
157  {
158  log(Error) << "Category '" << categoryName << "' is not an OCL category: type is '" << typeid(*p).name() << "'" << endlog();
159  }
160  else
161  {
162  log(Error) << "Category '" << categoryName << "' does not exist!" << endlog();
163  }
164  ok = false;
165  break;
166  }
167 
168  // find appender
169  RTT::TaskContext* appender = getPeer(appenderName);
170  if (appender)
171  {
172  // connect category port with appender port
173  RTT::base::PortInterface* appenderPort = 0;
174 
175  appenderPort = appender->ports()->getPort("LogPort");
176  if (appenderPort)
177  {
178  // \todo make connection policy configurable (from xml).
179  ConnPolicy cp = ConnPolicy::buffer(100,ConnPolicy::LOCK_FREE,false,false);
180  if ( appenderPort->connectTo( &(category->log_port), cp) )
181  {
182  std::stringstream str;
183  str << "Category '" << categoryName
184  << "' has appender '" << appenderName << "'"
185  << " with level "
186  << log4cpp::Priority::getPriorityName(category->getPriority());
187  log(Info) << str.str() << endlog();
188 // std::cout << str.str() << std::endl;
189  active_appenders.push_back(appenderName);
190  }
191  else
192  {
193  log(Error) << "Failed to connect port to appender '" << appenderName << "'" << endlog();
194  ok = false;
195  break;
196  }
197  }
198  else
199  {
200  log(Error) << "Failed to find log port in appender" << endlog();
201  ok = false;
202  break;
203  }
204  }
205  else
206  {
207  log(Error) << "Could not find appender '" << appenderName << "'" << endlog();
208  ok = false;
209  break;
210  }
211  }
212  }
213 
214  return ok;
215 }
216 
217 // NOT realtime
218 void LoggingService::logCategories()
219 {
220  std::vector<log4cpp::Category*>* categories =
221  log4cpp::Category::getCurrentCategories();
222  assert(categories);
223  std::vector<log4cpp::Category*>::iterator iter;
224  log(Info) << "Number categories = " << (int)categories->size() << endlog();
225  for (iter = categories->begin(); iter != categories->end(); ++iter)
226  {
227  std::stringstream str;
228 
229  str
230  << "Category '" << (*iter)->getName() << "', level="
231  << log4cpp::Priority::getPriorityName((*iter)->getPriority())
232  << ", typeid='"
233  << typeid(*iter).name()
234  << "', type really is '"
235  << std::string(0 != dynamic_cast<OCL::logging::Category*>(*iter)
236  ? "OCL::Category" : "log4cpp::Category")
237  << "', additivity=" << (const char*)((*iter)->getAdditivity()?"yes":"no");
238  log4cpp::Category* p = (*iter)->getParent();
239  if (p)
240  {
241  str << ", parent name='" << p->getName() << "'";
242  }
243  else
244  {
245  str << ", No parent";
246  }
247 
248  log(Info) << str.str() << endlog();
249  }
250 }
251 
252 // namespaces
253 }
254 }
255 
256 ORO_CREATE_COMPONENT_TYPE();
257 ORO_LIST_COMPONENT_TYPE(OCL::logging::LoggingService);
STL namespace.
This component is responsible for reading the logging configuration setting up the logging categories...
This file contains the macros and definitions to create dynamically loadable components.
The Orocos Component Library.
Definition: Component.hpp:43
A real-time capable category.
Definition: Category.hpp:25
Definition: Category.hpp:10