// Copyright (C) 2009-2010 Institut de Robòtica i Informàtica Industrial, CSIC-UPC. // Author Sergi Hernandez (shernand@iri.upc.edu) // All rights reserved. // // This file is part of iriutils // iriutils is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. #ifndef _LOG_H #define _LOG_H #include <iostream> #include <fstream> #include <stdio.h> #include <string> #include <vector> #include "mutex.h" #include "ctime.h" /** * \brief Implementation of a log file * * This class allows easyliy handling log files in a class. The name of the * file in which to save the user messages is fixed at construction time, and * the corresponding file created. If a file with the same name already exists, * it is deleted and a new one is created. The file is opened at construction * time, and remains this way until the class is destroyed, even if the log is * disabled. * * The message logging for a class can be enabled or disabled at any time. When * enabled, the user can use the log() function to save messages into the file. * These messages will each have the time stamp in which they where written. When * disabled, the log() fnction will do nothing. * * The function is_enabled() make it possible to check if the log is enabled or * not. By default, the ./log/ directory is used to store all the log files. The * class provides a mutex object in order to avoid data corruption when multiple * threads try to log messages to this object. */ class CLog { private: /** * \brief Log file structure * * This structure hold all the information regarding the file. It is initialized * when the object is created and associated to the user provided filename. It * is not possible to modify this structure directly, it will by updated when the * log() function is used, and destroyed when the corresponding object is * destroyed. */ std::fstream log_file; /** * \brief Log filename * * This string contains the full name of the log file including the path and * default extension. It is initialized at construction time with the name * provided by the user and can not be modified afterwards. It is possible * to get the full filename using the get_filename() function. */ std::string filename; /** * \brief Enable flag * * Thif flag indicates if the particular log is enabled (true) or not (false). * Its default value is true, so that when a new object of this class is created, * it can immediatelly start logging user messages. */ bool enabled; /** * \brief A mutual exclusion object to properly handle the log file * * This object avoid that the messages written to the log file get corrupted due * to concurrent write operations to a single file from different threads. When a * thread wants to log a message, it first locks the mutex, then writes the message * and finally frees the mutex. */ CMutex access; /** * \brief A time object to create the time stamps * * This attribute is used to get the current computer time each time a new log entry * is created, and also output it in the desired format to be written into the log * file. This object is initialized each time the log() function is called and can * not be directlyy accessed by the user. */ CTime time_stamp; public: /** * \brief Constructor * * This function initializes the file structure and associates it with the filename * provided by the user. By default, both global and local enables are set to true. * The values of all the attributes after calling this constructor is as follows: * * - log_file: An initialized FILE structure. * - enable=true. * * \param filename a null-terminated string with the name of the log file to be * created. The memory necessary for this string must be allocated by the calling * process. The file name must not have any spaces or special character. The * filename must not have any extension, '.log' is automatically appended. * * This function throws a CLogException if there is any error. */ CLog(const std::string& filename); /** * \brief Function to enable the log * This function enable the particular log associated with the object. This function * sets the enable attribute to true. The log file is already created when this * function is called, and it is not affected by its call. * * This function throws an exception if there is any error. */ void enable(void); /** * \brief Function to disable the log * This function disables the particular log associated with the object. This function * sets the enable attribute to false. The log file is already created when this * function is called, and it is not affected by its call. * * This function throws a CLogException if there is any error. */ void disable(void); /** * \brief Function to check if the log is enabled * * This function checks if the message logging for the corresponding object is enabled * or not. * * This function throws a CLogException if there is any error. * * \return The state of the local enable, true if the particular log is enabled or false * otherwise. * */ bool is_enabled(void); /** * \brief Function to get the full filename * * This function returns the full filename of rthe log file including the path and the * extension. * * This function throws a CLogException if there is any error. * * \return A null terminated string with the full filename of the log file. * */ std::string get_filename(void); /** * \brief Function to set the time format * * This function sets the time format format to be used in each of the log * entries. * * \param format the time format to be used. See the documentation on the * ctimeformat enummeration type for more information. * */ void set_time_format(ctimeformat format); /** * \brief Function to get the time format * * This functions returns the current time format used to generate each of the log * entries in ctimeformat type. * * \return the current time format used. See the documentation on the ctimeformat * enummeration type for more information. * */ ctimeformat get_time_format(); /** * \brief Function to write a variable to the log * * This function writes the user variable to the log file together with the time stamp at * which the message has been logged. If the global enable is not set, or else, if it is * set but the local enable is not, this function does nothing. The only way to actually * log user messages is that both the local and global enables are set. * * This function throws a CLogException if there is any error. * * \param value any kind of basic C++ data types which provides an overloaded version of * the << operator (int, double, std::string, etc.). Vectors are not supported * by this function, use the log_vector() function instead. * */ template<class T> void log(const T& value) { this->access.enter(); this->time_stamp.set(); if (this->is_enabled()) this->log_file << "[" << this->time_stamp.getString() << "] - " << value << std::endl; this->access.exit(); } /** * \brief Function to write a vector of variable to the log * * This function writes the user vector to the log file together with the time stamp at * which the message has been logged. If the global enable is not set, or else, if it is * set but the local enable is not, this function does nothing. The only way to actually * log user messages is that both the local and global enables are set. * * This function throws a CLogException if there is any error. * * \param values a vector of any kind of basic C++ data types which provides an overloaded * version of the << operator (int, double, std::string, etc.). * */ template<class T> void log_vector(const std::vector<T>& values) { unsigned int i=0; this->access.enter(); this->time_stamp.set(); if (this->is_enabled()) { this->log_file << "[" << this->time_stamp.getString() << "] - "; for(i=0;i<values.size();i++) { this->log_file << values[i]; if(i<values.size()-1) this->log_file << ","; } this->log_file << std::endl; } this->access.exit(); } /** * \brief Destructor * * This function closes the log file even if it is locally or globally disabled. All the * associated memory is freed, but the value of the global enable is not modified * because there may exist other CLog objects still created. * * This function throws a CLogException if there is any error. */ ~CLog(); }; #endif