304 lines
7.7 KiB
C++
304 lines
7.7 KiB
C++
|
/*
|
||
|
* Copyright (C) 2012 Open Source Robotics Foundation
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*
|
||
|
*/
|
||
|
#include <string>
|
||
|
#include <boost/filesystem.hpp>
|
||
|
#include <boost/lexical_cast.hpp>
|
||
|
#include <boost/algorithm/string/regex.hpp>
|
||
|
#include <sstream>
|
||
|
|
||
|
#include "gazebo/common/Exception.hh"
|
||
|
#include "gazebo/common/Time.hh"
|
||
|
#include "gazebo/common/Console.hh"
|
||
|
|
||
|
#include "gazebo/gazebo_config.h"
|
||
|
|
||
|
using namespace gazebo;
|
||
|
using namespace common;
|
||
|
|
||
|
FileLogger gazebo::common::Console::log("");
|
||
|
Logger Console::msg("[Msg] ", 32, Logger::STDOUT);
|
||
|
Logger Console::err("[Err] ", 31, Logger::STDERR);
|
||
|
Logger Console::dbg("[Dbg] ", 36, Logger::STDOUT);
|
||
|
Logger Console::warn("[Wrn] ", 33, Logger::STDERR);
|
||
|
|
||
|
bool Console::quiet = true;
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
void Console::SetQuiet(bool _quiet)
|
||
|
{
|
||
|
quiet = _quiet;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////
|
||
|
bool Console::GetQuiet()
|
||
|
{
|
||
|
return quiet;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
Logger::Logger(const std::string &_prefix, int _color, LogType _type)
|
||
|
: std::ostream(new Buffer(_type, _color)), color(_color), prefix(_prefix)
|
||
|
{
|
||
|
this->setf(std::ios_base::unitbuf);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
Logger::~Logger()
|
||
|
{
|
||
|
delete this->rdbuf();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
Logger &Logger::operator()()
|
||
|
{
|
||
|
Console::log << "(" << Time::GetWallTime() << ") ";
|
||
|
(*this) << this->prefix;
|
||
|
|
||
|
return (*this);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
Logger &Logger::operator()(const std::string &_file, int _line)
|
||
|
{
|
||
|
int index = _file.find_last_of("/") + 1;
|
||
|
|
||
|
Console::log << "(" << Time::GetWallTime() << ") ";
|
||
|
std::stringstream prefixString;
|
||
|
prefixString << this->prefix
|
||
|
<< "[" << _file.substr(index , _file.size() - index) << ":"
|
||
|
<< _line << "] ";
|
||
|
(*this) << prefixString.str();
|
||
|
|
||
|
return (*this);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
Logger::Buffer::Buffer(LogType _type, int _color)
|
||
|
: type(_type), color(_color)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
Logger::Buffer::~Buffer()
|
||
|
{
|
||
|
// Can't throw from a destructor
|
||
|
try
|
||
|
{
|
||
|
this->pubsync();
|
||
|
}
|
||
|
catch(...)
|
||
|
{
|
||
|
std::cerr << "Exception thrown while pubsync'ing Buffer" << std::endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
int Logger::Buffer::sync()
|
||
|
{
|
||
|
// Log messages to disk
|
||
|
Console::log << this->str();
|
||
|
Console::log.flush();
|
||
|
|
||
|
// Output to terminal
|
||
|
if (!Console::GetQuiet())
|
||
|
{
|
||
|
if (this->type == Logger::STDOUT)
|
||
|
{
|
||
|
#ifndef _WIN32
|
||
|
std::cout << "\033[1;" << this->color << "m" << this->str() << "\033[0m";
|
||
|
#else
|
||
|
std::cout << this->str();
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#ifndef _WIN32
|
||
|
std::cerr << "\033[1;" << this->color << "m" << this->str() << "\033[0m";
|
||
|
#else
|
||
|
std::cerr << this->str();
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this->str("");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
FileLogger::FileLogger(const std::string &_filename)
|
||
|
: std::ostream(new Buffer(_filename)),
|
||
|
logDirectory("")
|
||
|
{
|
||
|
this->setf(std::ios_base::unitbuf);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
FileLogger::~FileLogger()
|
||
|
{
|
||
|
delete this->rdbuf();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
void FileLogger::Init(const std::string &_prefix, const std::string &_filename)
|
||
|
{
|
||
|
if (!getenv("HOME"))
|
||
|
{
|
||
|
gzerr << "Missing HOME environment variable."
|
||
|
<< "No log file will be generated.";
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
FileLogger::Buffer *buf = static_cast<FileLogger::Buffer*>(
|
||
|
this->rdbuf());
|
||
|
|
||
|
boost::filesystem::path logPath(getenv("HOME"));
|
||
|
|
||
|
// Create a subdirectory for the informational log. The name of the directory
|
||
|
// will be <PREFIX><MASTER_PORT>. E.g.: server-11346. If the environment
|
||
|
// variable GAZEBO_MASTER_URI is not present or invalid, <MASTER_PORT> will
|
||
|
// be replaced by "default".
|
||
|
boost::filesystem::path subdir(_prefix + FileLogger::GetMasterPort());
|
||
|
logPath = logPath / ".gazebo/" / subdir;
|
||
|
|
||
|
// Create the log directory if it doesn't exist.
|
||
|
if (!boost::filesystem::exists(logPath))
|
||
|
boost::filesystem::create_directories(logPath);
|
||
|
|
||
|
logPath /= _filename;
|
||
|
|
||
|
// Check if the Init method has been already called, and if so
|
||
|
// remove current buffer.
|
||
|
if (buf->stream && buf->stream->is_open())
|
||
|
{
|
||
|
buf->stream->flush();
|
||
|
buf->stream->close();
|
||
|
}
|
||
|
|
||
|
// If the logPath is a directory, just rename it.
|
||
|
if (boost::filesystem::is_directory(logPath))
|
||
|
{
|
||
|
std::string newPath = logPath.string() + ".old";
|
||
|
boost::system::error_code ec;
|
||
|
boost::filesystem::rename(logPath, newPath, ec);
|
||
|
if (ec == boost::system::errc::success)
|
||
|
std::cerr << "Existing log directory [" << logPath
|
||
|
<< "] renamed to [" << newPath << "]" << std::endl;
|
||
|
else
|
||
|
{
|
||
|
std::cerr << "Unable to rename existing log directory [" << logPath
|
||
|
<< "] to [" << newPath << "]. Reason: " << ec.message();
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!buf->stream)
|
||
|
buf->stream = new std::ofstream(logPath.string().c_str(), std::ios::out);
|
||
|
else
|
||
|
buf->stream->open(logPath.string().c_str(), std::ios::out);
|
||
|
|
||
|
if (!buf->stream->is_open())
|
||
|
std::cerr << "Error opening log file: " << logPath << std::endl;
|
||
|
|
||
|
// Output the version of gazebo.
|
||
|
(*buf->stream) << GAZEBO_VERSION_HEADER << std::endl;
|
||
|
|
||
|
// Update the log directory name.
|
||
|
if (boost::filesystem::is_directory(logPath))
|
||
|
this->logDirectory = logPath.string();
|
||
|
else
|
||
|
this->logDirectory = logPath.branch_path().string();
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
FileLogger &FileLogger::operator()()
|
||
|
{
|
||
|
(*this) << "(" << Time::GetWallTime() << ") ";
|
||
|
return (*this);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
FileLogger &FileLogger::operator()(const std::string &_file, int _line)
|
||
|
{
|
||
|
int index = _file.find_last_of("/") + 1;
|
||
|
(*this) << "(" << Time::GetWallTime() << ") ["
|
||
|
<< _file.substr(index , _file.size() - index) << ":" << _line << "]";
|
||
|
|
||
|
return (*this);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
std::string FileLogger::GetMasterPort()
|
||
|
{
|
||
|
char *charURI = getenv("GAZEBO_MASTER_URI");
|
||
|
|
||
|
// Set to default port.
|
||
|
if (charURI && strlen(charURI) > 0)
|
||
|
{
|
||
|
std::string masterURI = charURI;
|
||
|
size_t lastColon = masterURI.find_last_of(":");
|
||
|
if (lastColon != std::string::npos && lastColon != masterURI.size() - 1)
|
||
|
return masterURI.substr(lastColon + 1, std::string::npos);
|
||
|
}
|
||
|
|
||
|
return boost::lexical_cast<std::string>(GAZEBO_DEFAULT_MASTER_PORT);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
std::string FileLogger::GetLogDirectory() const
|
||
|
{
|
||
|
return this->logDirectory;
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
FileLogger::Buffer::Buffer(const std::string &_filename)
|
||
|
: stream(NULL)
|
||
|
{
|
||
|
if (!_filename.empty())
|
||
|
{
|
||
|
this->stream = new std::ofstream(_filename.c_str(), std::ios::out);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
FileLogger::Buffer::~Buffer()
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
if (this->stream)
|
||
|
static_cast<std::ofstream*>(this->stream)->close();
|
||
|
delete this->stream;
|
||
|
}
|
||
|
catch(...)
|
||
|
{
|
||
|
std::cerr << "Exception thrown while closing Buffer" << std::endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////
|
||
|
int FileLogger::Buffer::sync()
|
||
|
{
|
||
|
if (!this->stream)
|
||
|
return -1;
|
||
|
|
||
|
*this->stream << this->str();
|
||
|
|
||
|
this->stream->flush();
|
||
|
|
||
|
this->str("");
|
||
|
return !(*this->stream);
|
||
|
}
|