Skip to content
Snippets Groups Projects
Commit e6ea621c authored by Steven Murray's avatar Steven Murray
Browse files

I have changed the design of the proposed new CASTOR logging API, from a C like

collection of functions within a castor::log namespace to a more object
oriented Singleton pattern.  Pleae note that the code is still far from
finished, I am commit (compiling) code early in an attempt to increase feedback.
parent 60dfc2c3
No related branches found
No related tags found
No related merge requests found
/******************************************************************************
* castor/log/Constants.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
*
* Copyright (C) 2003 CERN
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* 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 General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*
* Interface to the CASTOR logging system
*
* @author Steven.Murray@cern.ch
*****************************************************************************/
#ifndef CASTOR_LOG_CONSTANTS_HPP
#define CASTOR_LOG_CONSTANTS_HPP 1
#include <stdlib.h>
namespace castor {
namespace log {
/**
* Maximum length of the program name to be prepended to every log message.
*/
const size_t LOG_MAX_PROGNAMELEN = 20;
/**
* Parameter type: Double precision floating point value.
*/
const int LOG_MSG_PARAM_DOUBLE = 1;
/**
* Parameter type: 64 bit integer.
*/
const int LOG_MSG_PARAM_INT64 = 2;
/**
* Parameter type: General purpose string.
*/
const int LOG_MSG_PARAM_STR = 3;
/**
* Parameter type: Tape volume identifier string.
*/
const int LOG_MSG_PARAM_TPVID = 4;
/**
* Parameter type: Subrequest identifier.
*/
const int LOG_MSG_PARAM_UUID = 5;
/**
* Parameter type: Single precision floating point value.
*/
const int LOG_MSG_PARAM_FLOAT = 6;
/**
* Parameter type: Integer.
*/
const int LOG_MSG_PARAM_INT = 7;
/**
* Parameter type: User identifier as in getuid().
*/
const int LOG_MSG_PARAM_UID = 8;
/**
* Parameter type: Group identifier as in getgid().
*/
const int LOG_MSG_PARAM_GID = 9;
/**
* Parameter type: STYPE?
*/
const int LOG_MSG_PARAM_STYPE = 10;
/**
* Parameter type: SNAME?
*/
const int LOG_MSG_PARAM_SNAME = 11;
/**
* Parameter type: Raw (set of) parameters, in key=value format.
*/
const int LOG_MSG_PARAM_RAW = 12;
} // namespace log
} // namespace castor
#endif // CASTOR_LOG_CONSTANTS_HPP
This diff is collapsed.
/******************************************************************************
* Log.hpp
* castor/log/Log.hpp
*
* This file is part of the Castor project.
* See http://castor.web.cern.ch/castor
......@@ -20,18 +20,19 @@
*
* Interface to the CASTOR logging system
*
* @author Sebastien Ponce
* @author Steven.Murray@cern.ch
*****************************************************************************/
#ifndef CASTOR_LOG_LOG_HPP
#define CASTOR_LOG_LOG_HPP 1
// Include Files
#include "castor/exception/AlreadyInitialized.hpp"
#include "castor/exception/Internal.hpp"
#include "castor/exception/InvalidArgument.hpp"
#include "castor/log/Param.hpp"
#include <map>
#include <pthread.h>
#include <syslog.h>
#include <sys/time.h>
......@@ -39,96 +40,291 @@ namespace castor {
namespace log {
/**
* Maximum length of the program name to be prepended to every log message.
*/
const size_t LOG_MAX_PROGNAMELEN = 20;
/**
* Initialize the CASTOR logging interface.
*
* @param progname The name of the program to be prepended to every log message.
* The name should not be longer than castor::log::LOG_MAX_PROGNAMELEN
* characters.
*/
void initLog (const std::string &progname)
throw(castor::exception::AlreadyInitialized, castor::exception::Internal,
castor::exception::InvalidArgument);
/**
* Writes a message into the CASTOR logging system. Note that no exception
* will ever be thrown in case of failure. Failures will actually be
* silently ignored in order to not impact the processing.
* Class representing the CASTOR logging system.
*
* Note that this version of writeMsg() allows the caller to specify the
* time stamp of the log message.
* This class follows the singleton design-pattern because only one instance of
* this object should be created.
*
* @param priority the priority of the message.
* @param msg the message.
* @param numParams the number of parameters in the message.
* @param params the parameters of the message, given as an array.
* @param timeStamp the time stamp of the log message.
* For performance reasons it is recommended to only call the instance()
* method once in the main thread of the program, because the instance()
* method uses a mutex to protect the creation of the Log singleton.
*/
void writeMsg(const int priority,
const std::string &msg,
const int numParams,
const Param params[],
const struct timeval &timeStamp) throw();
class Log {
public:
/**
* A template function that wraps writeMsg in order to get the compiler
* to automatically determine the size of the params parameter, therefore
*
* Note that this version of writeMsg() allows the caller to specify the
* time stamp of the log message.
*
* @param msg the message.
* @param params the parameters of the message, given as an array.
* @param timeStamp the time stamp of the log message.
*/
template<int numParams>
void writeMsg(const int priority,
const std::string &msg,
castor::log::Param(&params)[numParams],
const struct timeval &timeStamp) throw() {
writeMsg(priority, msg, numParams, params, timeStamp);
}
/**
* Returns a reference to the object reprsenting the CASTOR logging
* system. If the object does not already exist then this method creates it.
*
* For performance reasons it is recommended to only call the instance()
* method once in the main thread of the program, because the instance()
* method uses a mutex to protect the creation of the Log singleton.
*
* @param programName The name of the program to be prepended to every log
* message. The name should not be longer than
* castor::log::LOG_MAX_PROGNAMELEN characters.
*/
static Log &instance(const std::string &programName)
throw(castor::exception::Internal, castor::exception::InvalidArgument);
/**
* Writes a message into the CASTOR logging system. Note that no exception
* will ever be thrown in case of failure. Failures will actually be
* silently ignored in order to not impact the processing.
*
* Note that this version of writeMsg() implicitly uses the current time as
* the time stamp of the message.
*
* @param priority the priority of the message.
* @param msg the message.
* @param numParams the number of parameters in the message.
* @param params the parameters of the message, given as an array.
*/
void writeMsg(const int priority,
const std::string &msg,
const int numParams,
const castor::log::Param params[]) throw();
/**
* Destroys the Log singleton if it exists. A subsequent call to instance()
* will create a new Log singleton.
*
* WARNING
* If you are not sure whether you should be using this method then please
* do not use it. You must be sure that no thread will try to use the
* Log singleton that was destoyed by a call to destroyInstance(). This
* method is intended to be used at cleanup time just before an executable
* exits. Calling this method just before an executable exits will free heap
* memory owned by the CASTOR logging system and therefore a memory profiler
* should not detect a memory leak related to the logging system.
*/
static void destroyInstance() throw(castor::exception::Internal);
/**
* A template function that wraps writeMsg in order to get the compiler
* to automatically determine the size of the params parameter, therefore
* removing the need for the devloper to provide it explicity.
*
* Note that this version of writeMsg() implicitly uses the current time as
* the time stamp of the message.
*
* @param priority the priority of the message.
* @param msg the message.
* @param params the parameters of the message, given as an array.
*/
template<int numParams>
void writeMsg(const int priority,
const std::string &msg,
castor::log::Param(&params)[numParams]) throw() {
writeMsg(priority, msg, numParams, params);
}
/**
* Writes a message into the CASTOR logging system. Note that no exception
* will ever be thrown in case of failure. Failures will actually be
* silently ignored in order to not impact the processing.
*
* Note that this version of writeMsg() allows the caller to specify the
* time stamp of the log message.
*
* @param priority the priority of the message as defined by the syslog API.
* @param msg the message.
* @param numParams the number of parameters in the message.
* @param params the parameters of the message.
* @param timeStamp the time stamp of the log message.
*/
void writeMsg(
const int priority,
const std::string &msg,
const int numParams,
const Param params[],
const struct timeval &timeStamp) throw();
/**
* A template function that wraps writeMsg in order to get the compiler
* to automatically determine the size of the params parameter, therefore
*
* Note that this version of writeMsg() allows the caller to specify the
* time stamp of the log message.
*
* @param priority the priority of the message as defined by the syslog API.
* @param msg the message.
* @param params the parameters of the message.
* @param timeStamp the time stamp of the log message.
*/
template<int numParams> void writeMsg(
const int priority,
const std::string &msg,
castor::log::Param(&params)[numParams],
const struct timeval &timeStamp) throw() {
writeMsg(priority, msg, numParams, params, timeStamp);
}
/**
* Writes a message into the CASTOR logging system. Note that no exception
* will ever be thrown in case of failure. Failures will actually be
* silently ignored in order to not impact the processing.
*
* Note that this version of writeMsg() implicitly uses the current time as
* the time stamp of the message.
*
* @param priority the priority of the message as defined by the syslog API.
* @param msg the message.
* @param numParams the number of parameters in the message.
* @param params the parameters of the message.
*/
void writeMsg(
const int priority,
const std::string &msg,
const int numParams,
const castor::log::Param params[]) throw();
/**
* A template function that wraps writeMsg in order to get the compiler
* to automatically determine the size of the params parameter, therefore
* removing the need for the devloper to provide it explicity.
*
* Note that this version of writeMsg() implicitly uses the current time as
* the time stamp of the message.
*
* @param priority the priority of the message as defined by the syslog API.
* @param msg the message.
* @param params the parameters of the message.
*/
template<int numParams> void writeMsg(
const int priority,
const std::string &msg,
castor::log::Param(&params)[numParams]) throw() {
writeMsg(priority, msg, numParams, params);
}
private:
/**
* Default size of a syslog message.
*/
static const size_t DEFAULT_SYSLOG_MSGLEN = 1024;
/**
* Default size of a rsyslog message.
*/
static const size_t DEFAULT_RSYSLOG_MSGLEN = 2000;
/**
* Maximum length of a parameter name.
*/
static const size_t LOG_MAX_PARAMNAMELEN = 20;
/**
* Maximum length of a string value.
*/
static const size_t LOG_MAX_PARAMSTRLEN = 1024;
/**
* Maximum length of a log message.
*/
static const size_t LOG_MAX_LINELEN = 8192;
/**
* Mutex to protect the s_instance variable.
*/
static pthread_mutex_t s_instanceMutex;
/**
* Pointer to the single instance of the Log class or NULL if one has not
* been created yet.
*/
static Log *s_instance;
/**
* Throws castor::exception::InvalidArgument if the specified program name is
* too long.
*/
static void checkProgramNameLen(const std::string &programName)
throw(castor::exception::InvalidArgument);
/**
* The name of the program to be prepended to every log message.
*/
const std::string m_programName;
/**
* The maximum message length that the client syslog server can handle.
*/
const size_t m_maxMsgLen;
/**
* Mutex used to protect the critical section of the Log object.
*/
pthread_mutex_t m_mutex;
/**
* The file descriptor of the socket used to send messages to syslog.
*/
int m_logFile;
/**
* True if there is currrently a connection with syslog.
*/
bool m_connected;
/**
* Map from syslog integer priority to textual representation.
*/
const std::map<int, std::string> m_priorityToText;
/**
* Private constructor that prevents clients from creating more than once
* instance of the Log class.
*
* @param programName The name of the program to be prepended to every log
* message.
*/
Log(const std::string &programName) throw(castor::exception::Internal);
/**
* Determines the maximum message length that the client syslog server can
* handle.
*
* @return The maximum message length that the client syslog server can
* handle.
*/
size_t determineMaxMsgLen() const throw();
/**
* Generates and returns the mapping between syslog priorities and their
* textual representations.
*/
std::map<int, std::string> generatePriorityToTextMap() const
throw(castor::exception::Internal);
/**
* Initializes the mutex used to protect the critical section of the Log
* object.
*/
void initMutex() throw(castor::exception::Internal);
/**
* Connects to syslog.
*
* Please note that this method must be called from within the critical
* section of the Log object.
*
* If the connection with syslog is already open then this method does
* nothing.
*
* This method does not throw an exception if the connection cannot be made
* to syslog. In this case the internal state of the Log object reflects the
* fact that no connection was made.
*/
void openLog() throw();
/**
* Build the header of a syslog message.
*/
int buildSyslogHeader(
char *const buffer,
const int buflen,
const int priority,
const struct timeval &timeStamp,
const int pid) const throw();
/**
* Creates a clean version of the specified string ready for use with syslog.
*
* @param s The string to be cleaned.
* @param replaceSpaces Set to true if spaces should be replaced by
* underscores.
* @return A cleaned version of the string.
*/
std::string cleanString(const std::string &s, const bool replaceSpaces)
throw();
/**
* A reduced version of syslog. This method is able to set the message
* timestamp. This is necessary when logging messages asynchronously of there
* creation, such as when retrieving logs from the DB.
*
* @param msg The message to be logged.
* @param msgLen The length of the message top be logged.
*/
void reducedSyslog(const char *const msg, const int msgLen) throw();
/**
* Closes the connection to syslog.
*
* Please note that this method must be called from within the critical
* section of the Log object.
*
* If the connection to syslog is already closed then this method does
* nothing.
*/
void closeLog() throw();
}; // class Log
} // namespace log
} // namespace castor
......
......@@ -28,6 +28,7 @@
#include <string.h>
#include <iomanip>
#include "castor/log/Constants.hpp"
#include "castor/log/Param.hpp"
#include "castor/ObjectSet.hpp"
......
......@@ -20,13 +20,12 @@
*
* A parameter for the CASTOR log system
*
* @author castor dev team
* @author Steven.Murray@cern.ch
*****************************************************************************/
#ifndef CASTOR_LOG_PARAM_HPP
#define CASTOR_LOG_PARAM_HPP 1
// Include Files
#include "castor/IObject.hpp"
#include "castor/stager/TapeVid.hpp"
#include "castor/log/IPAddress.hpp"
......@@ -36,20 +35,6 @@
#include <string.h>
#include <stdlib.h>
/* Parameter types */
#define LOG_MSG_PARAM_DOUBLE 1 /* Double precision floating point value */
#define LOG_MSG_PARAM_INT64 2 /* 64 bit integers */
#define LOG_MSG_PARAM_STR 3 /* General purpose string */
#define LOG_MSG_PARAM_TPVID 4 /* Tape visual identifier string */
#define LOG_MSG_PARAM_UUID 5 /* Subrequest identifier */
#define LOG_MSG_PARAM_FLOAT 6 /* Single precision floating point value */
#define LOG_MSG_PARAM_INT 7 /* Integer parameter */
#define LOG_MSG_PARAM_UID 8
#define LOG_MSG_PARAM_GID 9
#define LOG_MSG_PARAM_STYPE 10
#define LOG_MSG_PARAM_SNAME 11
#define LOG_MSG_PARAM_RAW 12 /* raw (set of) parameters, in key=value format */
namespace castor {
namespace log {
......@@ -78,20 +63,12 @@ public:
/**
* Constructor for long int.
*/
#if defined __x86_64__
Param(const std::string &name, const long int value) throw();
#else
Param(const std::string &name, const long int value) throw();
#endif
/**
* Constructor for long unsigned int.
*/
#if defined __x86_64__
Param(const std::string &name, const long unsigned int value) throw();
#else
Param(const std::string &name, const long unsigned int value) throw();
#endif
/**
* Constructor for int.
......
......@@ -22,6 +22,7 @@
* @author Steven.Murray@cern.ch
*****************************************************************************/
#include "castor/log/Constants.hpp"
#include "castor/log/Log.hpp"
#include <cppunit/extensions/HelperMacros.h>
......@@ -35,6 +36,7 @@ public:
}
void tearDown() {
Log::destroyInstance();
}
void testInitLog() {
......@@ -46,15 +48,11 @@ public:
CPPUNIT_ASSERT_THROW_MESSAGE(
"Checking a program name that is too long throws InvalidArgument",
initLog(tooLongProgname),
Log::instance(tooLongProgname),
castor::exception::InvalidArgument);
CPPUNIT_ASSERT_NO_THROW_MESSAGE(
"Checking the first call to initLog() does not fail",
initLog("LogTest"));
CPPUNIT_ASSERT_THROW_MESSAGE(
"Checking the second call to initLog() throws AlreadyInitialized",
initLog("LogTest"),
castor::exception::AlreadyInitialized);
Log::instance("LogTest"));
}
CPPUNIT_TEST_SUITE(LogTest);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment