Goby v2
application_base.cpp
1 // Copyright 2009-2018 Toby Schneider (http://gobysoft.org/index.wt/people/toby)
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 // Community contributors (see AUTHORS file)
5 //
6 //
7 // This file is part of the Goby Underwater Autonomy Project Libraries
8 // ("The Goby Libraries").
9 //
10 // The Goby Libraries are free software: you can redistribute them and/or modify
11 // them under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 2.1 of the License, or
13 // (at your option) any later version.
14 //
15 // The Goby Libraries are distributed in the hope that they will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with Goby. If not, see <http://www.gnu.org/licenses/>.
22 
23 #include <boost/filesystem.hpp>
24 #include <boost/format.hpp>
25 
26 #include "application_base.h"
27 #include "core_helpers.h"
28 #include "goby/common/configuration_reader.h"
29 #include <csignal>
30 
31 using goby::util::as;
32 
33 using goby::glog;
34 using namespace goby::common::logger;
35 
36 int goby::common::ApplicationBase::argc_ = 0;
37 char** goby::common::ApplicationBase::argv_ = 0;
38 
39 goby::common::ApplicationBase::ApplicationBase(google::protobuf::Message* cfg /*= 0*/)
40  : all_cfg_(cfg), base_cfg_(0), own_base_cfg_(false), alive_(true)
41 {
42  //
43  // read the configuration
44  //
45  boost::program_options::options_description od("Allowed options");
46  boost::program_options::variables_map var_map;
47  try
48  {
49  std::string application_name;
50  common::ConfigReader::read_cfg(argc_, argv_, cfg, &application_name, &od, &var_map);
51 
52  // extract the AppBaseConfig assuming the user provided it in their configuration
53  // .proto file
54  if (cfg)
55  {
56  const google::protobuf::Descriptor* desc = cfg->GetDescriptor();
57  for (int i = 0, n = desc->field_count(); i < n; ++i)
58  {
59  const google::protobuf::FieldDescriptor* field_desc = desc->field(i);
60  if (field_desc->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE &&
61  field_desc->message_type() == ::AppBaseConfig::descriptor())
62  {
63  base_cfg_ = dynamic_cast<AppBaseConfig*>(
64  cfg->GetReflection()->MutableMessage(cfg, field_desc));
65  }
66  }
67  }
68 
69  if (!base_cfg_)
70  {
71  base_cfg_ = new AppBaseConfig;
72  own_base_cfg_ = true;
73  }
74 
75  base_cfg_->set_app_name(application_name);
76  // incorporate some parts of the AppBaseConfig that are common
77  // with gobyd (e.g. Verbosity)
78  merge_app_base_cfg(base_cfg_, var_map);
79  }
80  catch (common::ConfigException& e)
81  {
82  // output all the available command line options
83  if (e.error())
84  {
85  std::cerr << od << "\n";
86  std::cerr << "Problem parsing command-line configuration: \n" << e.what() << "\n";
87  }
88  throw;
89  }
90 
91  // set up the logger
94  static_cast<common::logger::Verbosity>(base_cfg_->glog_config().tty_verbosity()),
95  &std::cout);
96 
97  if (base_cfg_->glog_config().show_gui())
98  glog.enable_gui();
99 
100  fout_.resize(base_cfg_->glog_config().file_log_size());
101  for (int i = 0, n = base_cfg_->glog_config().file_log_size(); i < n; ++i)
102  {
103  using namespace boost::posix_time;
104 
105  boost::format file_format(base_cfg_->glog_config().file_log(i).file_name());
106  file_format.exceptions(boost::io::all_error_bits ^
107  (boost::io::too_many_args_bit | boost::io::too_few_args_bit));
108 
109  std::string file_name = (file_format % to_iso_string(second_clock::universal_time())).str();
110  std::string file_symlink = (file_format % "latest").str();
111 
112  glog.is(VERBOSE) && glog << "logging output to file: " << file_name << std::endl;
113 
114  fout_[i].reset(new std::ofstream(file_name.c_str()));
115 
116  if (!fout_[i]->is_open())
117  glog.is(DIE) && glog << die
118  << "cannot write glog output to requested file: " << file_name
119  << std::endl;
120 
121  remove(file_symlink.c_str());
122  namespace fs = boost::filesystem;
123  fs::path canonicalized_file_name = fs::canonical(fs::path(file_name.c_str()));
124  symlink(canonicalized_file_name.string().c_str(), file_symlink.c_str());
125 
126  glog.add_stream(base_cfg_->glog_config().file_log(i).verbosity(), fout_[i].get());
127  }
128 
129  if (!base_cfg_->IsInitialized())
130  throw(common::ConfigException("Invalid base configuration"));
131 
132  glog.is(DEBUG1) && glog << "App name is " << application_name() << std::endl;
133 }
134 
135 goby::common::ApplicationBase::~ApplicationBase()
136 {
137  glog.is(DEBUG1) && glog << "ApplicationBase destructing..." << std::endl;
138 
139  if (own_base_cfg_)
140  delete base_cfg_;
141 }
142 
143 void goby::common::ApplicationBase::__run()
144 {
145  // block SIGWINCH (change window size) in all threads
146  sigset_t signal_mask;
147  sigemptyset(&signal_mask);
148  sigaddset(&signal_mask, SIGWINCH);
149  pthread_sigmask(SIG_BLOCK, &signal_mask, NULL);
150 
151  // continue to run while we are alive (quit() has not been called)
152  while (alive_)
153  {
154  // try
155  // {
156  iterate();
157  // }
158  // catch(std::exception& e)
159  // {
160  // glog.is(WARN) &&
161  // glog << e.what() << std::endl;
162  // }
163  }
164 }
void set_name(const std::string &s)
Set the name of the application that the logger is serving.
Definition: flex_ostream.h:67
std::string application_name()
name of this application (from AppBaseConfig::app_name). E.g. "garmin_gps_g"
common::FlexOstream glog
Access the Goby logger through this object.
void add_stream(logger::Verbosity verbosity=logger::VERBOSE, std::ostream *os=0)
Attach a stream object (e.g. std::cout, std::ofstream, ...) to the logger with desired verbosity...
Definition: flex_ostream.h:96