All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
Console.cpp
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2008, 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 
35 /* Author: Ioan Sucan */
36 
37 #include "ompl/util/Console.h"
38 #include <boost/thread/mutex.hpp>
39 #include <iostream>
40 #include <cstdio>
41 #include <cstdarg>
42 
44 
45 struct DefaultOutputHandler
46 {
47  DefaultOutputHandler(void)
48  {
49  output_handler_ = static_cast<ompl::msg::OutputHandler*>(&std_output_handler_);
50  previous_output_handler_ = output_handler_;
51  logLevel_ = ompl::msg::LOG_DEBUG;
52  }
53 
54  ompl::msg::OutputHandlerSTD std_output_handler_;
55  ompl::msg::OutputHandler *output_handler_;
56  ompl::msg::OutputHandler *previous_output_handler_;
57  ompl::msg::LogLevel logLevel_;
58  boost::mutex lock_; // it is likely the outputhandler does some I/O, so we serialize it
59 };
60 
61 // we use this function because we want to handle static initialization correctly
62 // however, the first run of this function is not thread safe, due to the use of a static
63 // variable inside the function. For this reason, we ensure the first call happens during
64 // static initialization using a proxy class
65 static DefaultOutputHandler* getDOH(void)
66 {
67  static DefaultOutputHandler DOH;
68  return &DOH;
69 }
70 
71 #define USE_DOH \
72  DefaultOutputHandler *doh = getDOH(); \
73  boost::mutex::scoped_lock slock(doh->lock_)
74 
75 #define MAX_BUFFER_SIZE 1024
76 
78 
80 {
81  USE_DOH;
82  doh->previous_output_handler_ = doh->output_handler_;
83  doh->output_handler_ = NULL;
84 }
85 
87 {
88  USE_DOH;
89  std::swap(doh->previous_output_handler_, doh->output_handler_);
90 }
91 
93 {
94  USE_DOH;
95  doh->previous_output_handler_ = doh->output_handler_;
96  doh->output_handler_ = oh;
97 }
98 
100 {
101  return getDOH()->output_handler_;
102 }
103 
104 void ompl::msg::log(const char *file, int line, LogLevel level, const char* m, ...)
105 {
106  USE_DOH;
107  if (doh->output_handler_ && level >= doh->logLevel_)
108  {
109  va_list __ap;
110  va_start(__ap, m);
111  char buf[MAX_BUFFER_SIZE];
112  vsnprintf(buf, sizeof(buf), m, __ap);
113  va_end(__ap);
114  buf[MAX_BUFFER_SIZE - 1] = '\0';
115 
116  doh->output_handler_->log(buf, level, file, line);
117  }
118 }
119 
121 {
122  USE_DOH;
123  doh->logLevel_ = level;
124 }
125 
127 {
128  USE_DOH;
129  return doh->logLevel_;
130 }
131 
132 static const char* LogLevelString[4] = {"Debug: ", "Info: ", "Warning: ", "Error: "};
133 
134 void ompl::msg::OutputHandlerSTD::log(const std::string &text, LogLevel level, const char *filename, int line)
135 {
136  if (level >= LOG_WARN)
137  {
138  std::cerr << LogLevelString[level] << text << std::endl;
139  std::cerr << " at line " << line << " in " << filename << std::endl;
140  std::cerr.flush();
141  }
142  else
143  {
144  std::cout << LogLevelString[level] << text << std::endl;
145  std::cout.flush();
146  }
147 }
148 
150 {
151  file_ = fopen(filename, "a");
152  if (!file_)
153  std::cerr << "Unable to open log file: '" << filename << "'" << std::endl;
154 }
155 
156 ompl::msg::OutputHandlerFile::~OutputHandlerFile(void)
157 {
158  if (file_)
159  if (fclose(file_) != 0)
160  std::cerr << "Error closing logfile" << std::endl;
161 }
162 
163 void ompl::msg::OutputHandlerFile::log(const std::string &text, LogLevel level, const char *filename, int line)
164 {
165  if (file_)
166  {
167  fprintf(file_, "%s%s\n", LogLevelString[level], text.c_str());
168  if(level >= LOG_WARN)
169  fprintf(file_, " at line %d in %s\n", line, filename);
170  fflush(file_);
171  }
172 }