generic_analyzer.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2009, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
38 
39 using namespace diagnostic_aggregator;
40 using namespace std;
41 
44 
45 
47 
48 bool GenericAnalyzer::init(const string base_path, const ros::NodeHandle &n)
49 {
50  string nice_name;
51  if (!n.getParam("path", nice_name))
52  {
53  ROS_ERROR("GenericAnalyzer was not given parameter \"path\". Namepspace: %s",
54  n.getNamespace().c_str());
55  return false;
56  }
57 
58  XmlRpc::XmlRpcValue find_remove;
59  if (n.getParam("find_and_remove_prefix", find_remove))
60  {
61  vector<string> output;
62  getParamVals(find_remove, output);
63  chaff_ = output;
64  startswith_ = output;
65  }
66 
67  XmlRpc::XmlRpcValue removes;
68  if (n.getParam("remove_prefix", removes))
69  getParamVals(removes, chaff_);
70 
71  XmlRpc::XmlRpcValue startswith;
72  if (n.getParam("startswith", startswith))
73  getParamVals(startswith, startswith_);
74 
75  XmlRpc::XmlRpcValue name_val;
76  if (n.getParam("name", name_val))
77  getParamVals(name_val, name_);
78 
79  XmlRpc::XmlRpcValue contains;
80  if (n.getParam("contains", contains))
81  getParamVals(contains, contains_);
82 
83  XmlRpc::XmlRpcValue expected;
84  if (n.getParam("expected", expected))
85  {
86  getParamVals(expected, expected_);
87  for (unsigned int i = 0; i < expected_.size(); ++i)
88  {
89  boost::shared_ptr<StatusItem> item(new StatusItem(expected_[i]));
90  addItem(expected_[i], item);
91  }
92  }
93 
94  XmlRpc::XmlRpcValue regexes;
95  if (n.getParam("regex", regexes))
96  {
97  vector<string> regex_strs;
98  getParamVals(regexes, regex_strs);
99 
100  for (unsigned int i = 0; i < regex_strs.size(); ++i)
101  {
102  try
103  {
104  boost::regex re(regex_strs[i]);
105  regex_.push_back(re);
106  }
107  catch (boost::regex_error& e)
108  {
109  ROS_ERROR("Attempted to make regex from %s. Caught exception, ignoring value. Exception: %s",
110  regex_strs[i].c_str(), e.what());
111  }
112  }
113  }
114 
115  if (startswith_.size() == 0 && name_.size() == 0 &&
116  contains_.size() == 0 && expected_.size() == 0 && regex_.size() == 0)
117  {
118  ROS_ERROR("GenericAnalyzer was not initialized with any way of checking diagnostics. Name: %s, namespace: %s", nice_name.c_str(), n.getNamespace().c_str());
119  return false;
120  }
121 
122  // convert chaff_ to output name format. Fixes #17
123  for(size_t i=0; i<chaff_.size(); i++) {
124  chaff_[i] = getOutputName(chaff_[i]);
125  }
126 
127  double timeout;
128  int num_items_expected;
129  bool discard_stale;
130  n.param("timeout", timeout, 5.0); // Timeout for stale
131  n.param("num_items", num_items_expected, -1); // Number of items must match this
132  n.param("discard_stale", discard_stale, false);
133 
134  string my_path;
135  if (base_path == "/")
136  my_path = nice_name;
137  else
138  my_path = base_path + "/" + nice_name;
139 
140  if (my_path.find("/") != 0)
141  my_path = "/" + my_path;
142 
143  return GenericAnalyzerBase::init(my_path, nice_name,
144  timeout, num_items_expected, discard_stale);
145 }
146 
148 
149 
150 bool GenericAnalyzer::match(const string name)
151 {
152  boost::cmatch what;
153  for (unsigned int i = 0; i < regex_.size(); ++i)
154  {
155  if (boost::regex_match(name.c_str(), what, regex_[i]))
156  return true;
157  }
158 
159  for (unsigned int i = 0; i < expected_.size(); ++i)
160  {
161  if (name == expected_[i])
162  return true;
163  }
164 
165  for (unsigned int i = 0; i < name_.size(); ++i)
166  {
167  if (name == name_[i])
168  return true;
169  }
170 
171  for (unsigned int i = 0; i < startswith_.size(); ++i)
172  {
173  if (name.find(startswith_[i]) == 0)
174  return true;
175  }
176 
177  for (unsigned int i = 0; i < contains_.size(); ++i)
178  {
179  if (name.find(contains_[i]) != string::npos)
180  return true;
181  }
182 
183  return false;
184 }
185 
186 vector<boost::shared_ptr<diagnostic_msgs::DiagnosticStatus> > GenericAnalyzer::report()
187 {
188  vector<boost::shared_ptr<diagnostic_msgs::DiagnosticStatus> > processed = GenericAnalyzerBase::report();
189 
190  // Check and make sure our expected names haven't been removed ...
191  vector<string> expected_names_missing;
192  bool has_name = false;
193 
194  for (unsigned int i = 0; i < expected_.size(); ++i)
195  {
196  has_name = false;
197  for (unsigned int j = 0; j < processed.size(); ++j)
198  {
199  size_t last_slash = processed[j]->name.rfind("/");
200  string nice_name = processed[j]->name.substr(last_slash + 1);
201  if (nice_name == expected_[i] || nice_name == getOutputName(expected_[i]))
202  {
203  has_name = true;
204  break;
205  }
206 
207  // Remove chaff, check names
208  for (unsigned int k = 0; k < chaff_.size(); ++k)
209  {
210  if (nice_name == removeLeadingNameChaff(expected_[i], chaff_[k]))
211  {
212  has_name = true;
213  break;
214  }
215  }
216 
217  }
218  if (!has_name)
219  expected_names_missing.push_back(expected_[i]);
220  }
221 
222  // Check that all processed items aren't stale
223  bool all_stale = true;
224  for (unsigned int j = 0; j < processed.size(); ++j)
225  {
226  if (processed[j]->level != 3)
227  all_stale = false;
228  }
229 
230  // Add missing names to header ...
231  for (unsigned int i = 0; i < expected_names_missing.size(); ++i)
232  {
233  boost::shared_ptr<StatusItem> item(new StatusItem(expected_names_missing[i]));
234  processed.push_back(item->toStatusMsg(path_, true));
235  }
236 
237  for (unsigned int j = 0; j < processed.size(); ++j)
238  {
239  // Remove all leading name chaff
240  for (unsigned int i = 0; i < chaff_.size(); ++i)
241  processed[j]->name = removeLeadingNameChaff(processed[j]->name, chaff_[i]);
242 
243  // If we're missing any items, set the header status to error or stale
244  if (expected_names_missing.size() > 0 && processed[j]->name == path_)
245  {
246  if (!all_stale)
247  {
248  processed[j]->level = 2;
249  processed[j]->message = "Error";
250  }
251  else
252  {
253  processed[j]->level = 3;
254  processed[j]->message = "All Stale";
255  }
256 
257  // Add all missing items to header item
258  for (unsigned int k = 0; k < expected_names_missing.size(); ++k)
259  {
260  diagnostic_msgs::KeyValue kv;
261  kv.key = expected_names_missing[k];
262  kv.value = "Missing";
263  processed[j]->values.push_back(kv);
264  }
265  }
266  }
267 
268  return processed;
269 }
PLUGINLIB_EXPORT_CLASS(diagnostic_aggregator::GenericAnalyzer, diagnostic_aggregator::Analyzer) GenericAnalyzer
virtual std::vector< boost::shared_ptr< diagnostic_msgs::DiagnosticStatus > > report()
Reports current state, returns vector of formatted status messages.
std::string name_
Definition: gtest-all.cc:3761
GenericAnalyzer is most basic diagnostic Analyzer.
virtual std::vector< boost::shared_ptr< diagnostic_msgs::DiagnosticStatus > > report()
Reports current state, returns vector of formatted status messages.
std::string removeLeadingNameChaff(const std::string &input_name, const std::string &chaff)
Removes redundant prefixes from status name.
Definition: status_item.h:127
virtual bool match(const std::string name)
Returns true if item matches any of the given criteria.
bool param(const std::string &param_name, T &param_val, const T &default_val) const
bool init(const std::string base_path, const ros::NodeHandle &n)
Initializes GenericAnalyzer from namespace. Returns true if s.
bool init(const std::string path, const ros::NodeHandle &n)=0
Analyzer is initialized with base path and namespace.
const std::string & getNamespace() const
bool getParamVals(XmlRpc::XmlRpcValue param, std::vector< std::string > &output)
Returns list of strings from a parameter.
Base class of all Analyzers. Loaded by aggregator.
Definition: analyzer.h:85
bool getParam(const std::string &key, std::string &s) const
Helper class to hold, store DiagnosticStatus messages.
Definition: status_item.h:158
std::string getOutputName(const std::string item_name)
Replace "/" with "" in output name, to avoid confusing robot monitor.
Definition: status_item.h:55
#define ROS_ERROR(...)


diagnostic_aggregator
Author(s): Kevin Watts, Brice Rebsamen
autogenerated on Thu Oct 8 2020 03:17:16