generic_analyzer_base.h
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2009, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00037 #ifndef GENERIC_ANALYZER_BASE_H
00038 #define GENERIC_ANALYZER_BASE_H
00039 
00040 #include <map>
00041 #include <ros/ros.h>
00042 #include <vector>
00043 #include <string>
00044 #include <sstream>
00045 #include <boost/shared_ptr.hpp>
00046 #include <boost/regex.hpp>
00047 #include <pluginlib/class_list_macros.hpp>
00048 #include "diagnostic_msgs/DiagnosticStatus.h"
00049 #include "diagnostic_msgs/KeyValue.h"
00050 #include "diagnostic_aggregator/analyzer.h"
00051 #include "diagnostic_aggregator/status_item.h"
00052 
00053 namespace diagnostic_aggregator {
00054 
00065 class GenericAnalyzerBase : public Analyzer
00066 {
00067 public:
00068   GenericAnalyzerBase() : 
00069     nice_name_(""), path_(""), timeout_(-1.0), num_items_expected_(-1),
00070     discard_stale_(false), has_initialized_(false), has_warned_(false) 
00071   { }
00072   
00073   virtual ~GenericAnalyzerBase() { items_.clear(); }
00074   
00075   /*
00076    *\brief Cannot be initialized from (string, NodeHandle) like defined Analyzers
00077    */
00078   bool init(const std::string path, const ros::NodeHandle &n) = 0;
00079 
00080   /*
00081    *\brief Must be initialized with path, and a "nice name"
00082    *
00083    * Must be initialized in order to prepend the path to all outgoing status messages.
00084    */
00085   bool init(const std::string path, const std::string nice_name, 
00086             double timeout = -1.0, int num_items_expected = -1, bool discard_stale = false)
00087   {
00088     num_items_expected_ = num_items_expected;
00089     timeout_ = timeout;
00090     nice_name_ = nice_name;
00091     path_ = path;
00092     discard_stale_ = discard_stale;
00093     last_header_status_change_ = ros::Time::now();
00094     last_header_level_ = 0;
00095 
00096     if (discard_stale_ && timeout <= 0)
00097     {
00098       ROS_WARN("Cannot discard stale items if no timeout specified. No items will be discarded");
00099       discard_stale_ = false;
00100     }
00101 
00102     has_initialized_ = true;
00103     
00104     return true;
00105   }
00106 
00110   virtual bool analyze(const boost::shared_ptr<StatusItem> item)
00111   {
00112     if (!has_initialized_ && !has_warned_)
00113     {
00114       has_warned_ = true;
00115       ROS_ERROR("GenericAnalyzerBase is asked to analyze diagnostics without being initialized. init() must be called in order to correctly use this class.");
00116     }
00117 
00118     if (!has_initialized_)
00119       return false;
00120 
00121     items_[item->getName()] = item;
00122 
00123     return has_initialized_;
00124   }
00125   
00131   virtual std::vector<boost::shared_ptr<diagnostic_msgs::DiagnosticStatus> > report()
00132   {
00133     if (!has_initialized_ && !has_warned_)
00134     {
00135       has_warned_ = true;
00136       ROS_ERROR("GenericAnalyzerBase is asked to report diagnostics without being initialized. init() must be called in order to correctly use this class.");
00137     }
00138     if (!has_initialized_)
00139     {
00140       std::vector<boost::shared_ptr<diagnostic_msgs::DiagnosticStatus> > vec;
00141       return vec;
00142     }
00143 
00144     boost::shared_ptr<diagnostic_msgs::DiagnosticStatus> header_status(new diagnostic_msgs::DiagnosticStatus());
00145     header_status->name = path_;
00146     header_status->level = 0;
00147     header_status->message = "OK";
00148     
00149     std::vector<boost::shared_ptr<diagnostic_msgs::DiagnosticStatus> > processed;
00150     processed.push_back(header_status);
00151     
00152     bool all_stale = true;
00153 
00154     std::map<std::string, boost::shared_ptr<StatusItem> >::iterator it = items_.begin();
00155     while(it != items_.end())
00156     {
00157       std::string name = it->first;
00158       boost::shared_ptr<StatusItem> item = it->second;
00159 
00160       bool stale = false;
00161       if (timeout_ > 0)
00162         stale = (ros::Time::now() - item->getLastUpdateTime()).toSec() > timeout_;
00163 
00164       // Erase item if its stale and we're discarding items
00165       if (discard_stale_ && stale)
00166       {
00167         items_.erase(it++);
00168         continue;
00169       }
00170       
00171       int8_t level = item->getLevel();
00172       header_status->level = std::max(header_status->level, level);
00173       
00174       diagnostic_msgs::KeyValue kv;
00175       kv.key = name;
00176       kv.value = item->getMessage();
00177       
00178       header_status->values.push_back(kv);
00179       
00180       all_stale = all_stale && ((level == 3) || stale);
00181       
00182       //boost::shared_ptr<diagnostic_msgs::DiagnosticStatus> stat = item->toStatusMsg(path_, stale);
00183       
00184       processed.push_back(item->toStatusMsg(path_, stale));
00185 
00186       if (stale)
00187         header_status->level = 3;
00188 
00189       ++it;
00190     }
00191     
00192     // Header is not stale unless all subs are
00193     if (all_stale)
00194       header_status->level = 3;
00195     else if (header_status->level == 3)
00196       header_status->level = 2;
00197     
00198     header_status->message = valToMsg(header_status->level);
00199     
00200     // If we expect a given number of items, check that we have this number
00201     if (num_items_expected_ == 0 && items_.size() == 0)
00202     {
00203       header_status->level = 0;
00204       header_status->message = "OK";
00205     }
00206     else if (num_items_expected_ > 0 && int(items_.size()) != num_items_expected_)
00207     {
00208       int8_t lvl = 2;
00209       header_status->level = std::max(lvl, header_status->level);
00210 
00211       std::stringstream expec, item;
00212       expec << num_items_expected_;
00213       item << items_.size();
00214 
00215       if (items_.size() > 0)
00216         header_status->message = "Expected " + expec.str() + ", found " + item.str();
00217       else
00218         header_status->message = "No items found, expected " + expec.str();
00219     }
00220     
00221     bool header_stale_timed_out = false;
00222     if (timeout_ > 0 && last_header_level_ == 3)
00223         header_stale_timed_out = (ros::Time::now() - last_header_status_change_).toSec() > timeout_;
00224 
00225     if (last_header_level_ != header_status->level)
00226     {
00227       last_header_status_change_ = ros::Time::now();
00228       last_header_level_ = header_status->level; // update the last header level
00229     }
00230 
00231     if (discard_stale_ && processed.size() == 1 && header_stale_timed_out)
00232     {
00233       std::vector<boost::shared_ptr<diagnostic_msgs::DiagnosticStatus> > vec;
00234       return vec;
00235     }
00236     
00237     return processed;
00238   }
00239 
00243   virtual bool match(const std::string name) = 0;
00244   
00248   virtual std::string getPath() const { return path_; }
00249 
00253   virtual std::string getName() const { return nice_name_; }
00254 
00255 protected:
00256   std::string nice_name_;
00257   std::string path_;
00258 
00259   double timeout_;
00260   int num_items_expected_;
00261 
00265   void addItem(std::string name, boost::shared_ptr<StatusItem> item)  { items_[name] = item; }
00266 
00267 private:
00271   std::map<std::string, boost::shared_ptr<StatusItem> > items_;
00272 
00273   bool discard_stale_, has_initialized_, has_warned_;
00274   ros::Time last_header_status_change_; // last timestamp at which the header of the returned diagnostic msg array changed
00275   int last_header_level_; // last level reported by the header of the returend diagnostic msg array
00276 
00277 };
00278 
00279 }
00280 #endif //GENERIC_ANALYZER_BASE_H


diagnostic_aggregator
Author(s): Kevin Watts, Brice Rebsamen
autogenerated on Tue Mar 26 2019 03:09:36