Commit c39c1190 authored by André Anjos's avatar André Anjos 💬
Browse files

First attempt to provide an API to the old logging functionality

parent 71f3221f
......@@ -34,7 +34,7 @@
#warning Disabling MT locks because Boost < 1.35!
#endif
#include "logging.h"
#include <bob.core/_logging_api.h>
bob::core::OutputDevice::~OutputDevice() {}
......@@ -168,26 +168,3 @@ boost::iostreams::stream<bob::core::AutoOutputDevice> bob::core::debug("stdout")
boost::iostreams::stream<bob::core::AutoOutputDevice> bob::core::info("stdout");
boost::iostreams::stream<bob::core::AutoOutputDevice> bob::core::warn("stderr");
boost::iostreams::stream<bob::core::AutoOutputDevice> bob::core::error("stderr");
std::string bob::core::tmpdir() {
const char* value = getenv("TMPDIR");
if (value) return value;
else return "/tmp";
}
std::string bob::core::tmpfile(const std::string& extension) {
boost::filesystem::path tpl = bob::core::tmpdir();
tpl /= std::string("bob_tmpfile_XXXXXX");
boost::shared_array<char> char_tpl(new char[tpl.string().size()+1]);
strcpy(char_tpl.get(), tpl.string().c_str());
#ifdef _WIN32
mktemp(char_tpl.get());
#else
int fd = mkstemp(char_tpl.get());
close(fd);
boost::filesystem::remove(char_tpl.get());
#endif
std::string res = char_tpl.get();
res += extension;
return res;
}
......@@ -10,8 +10,8 @@
* Copyright (C) Idiap Research Institute, Martigny, Switzerland
*/
#ifndef BOB_CORE_LOGGING_H
#define BOB_CORE_LOGGING_H
#ifndef BOB_CORE_LOGGING_API_H
#define BOB_CORE_LOGGING_API_H
#include <string>
#include <boost/iostreams/stream.hpp>
......@@ -24,131 +24,101 @@
* @addtogroup CORE core
* @brief Core module API
*/
namespace bob {
namespace bob { namespace core {
/**
* @ingroup CORE
* @brief The device is what tells the sink where to actually send the
* messages to. If the AutoOutputDevice does not have a device, the
* messages are discarded.
*/
namespace core {
struct OutputDevice {
/**
* @ingroup CORE
* @{
* @brief Virtual destructor.
*/
virtual ~OutputDevice();
/**
* @brief The device is what tells the sink where to actually send the
* messages to. If the AutoOutputDevice does not have a device, the
* messages are discarded.
* @brief Writes n bytes of data into this device
*/
struct OutputDevice {
virtual std::streamsize write(const char* s, std::streamsize n) =0;
/**
* @brief Closes this device
*/
virtual void close() {}
};
/**
* @brief Use this sink always in bob C++ programs. You can configure it
* to send messages to stdout, stderr, to a file or discard them.
*/
class AutoOutputDevice: public boost::iostreams::sink {
public:
/**
* @brief Virtual destructor.
* @brief C'tor, empty, discards all input.
*/
virtual ~OutputDevice();
AutoOutputDevice();
/**
* @brief Writes n bytes of data into this device
* @brief Creates a new sink using one of the built-in strategies.
* - null: discards all messages
* - stdout: send all messages to stdout
* - stderr: send all messages to stderr
* - filename: send all messages to the file named "filename"
* - filename.gz: send all messagses to the file named "filename.gz",
* in compressed format.
*
* @param configuration The configuration string to use for this sink
* as declared above
*/
virtual std::streamsize write(const char* s, std::streamsize n) =0;
AutoOutputDevice(const std::string& configuration);
/**
* @brief Closes this device
* @brief Intializes with a device.
*/
virtual void close() {}
};
AutoOutputDevice(boost::shared_ptr<OutputDevice> device);
/**
* @brief Use this sink always in bob C++ programs. You can configure it
* to send messages to stdout, stderr, to a file or discard them.
*/
class AutoOutputDevice: public boost::iostreams::sink {
public:
/**
* @brief C'tor, empty, discards all input.
*/
AutoOutputDevice();
/**
* @brief Creates a new sink using one of the built-in strategies.
* - null: discards all messages
* - stdout: send all messages to stdout
* - stderr: send all messages to stderr
* - filename: send all messages to the file named "filename"
* - filename.gz: send all messagses to the file named "filename.gz",
* in compressed format.
*
* @param configuration The configuration string to use for this sink
* as declared above
*/
AutoOutputDevice(const std::string& configuration);
/**
* @brief Intializes with a device.
*/
AutoOutputDevice(boost::shared_ptr<OutputDevice> device);
/**
* @brief D'tor
*/
virtual ~AutoOutputDevice();
/**
* @brief Forwards call to underlying OutputDevice
*/
virtual std::streamsize write(const char* s, std::streamsize n);
/**
* @brief Closes this base sink
*/
virtual void close();
private:
boost::shared_ptr<OutputDevice> m_device; ///< Who does the real job.
};
// standard streams
extern boost::iostreams::stream<AutoOutputDevice> debug;
extern boost::iostreams::stream<AutoOutputDevice> info;
extern boost::iostreams::stream<AutoOutputDevice> warn;
extern boost::iostreams::stream<AutoOutputDevice> error;
/**
* @brief D'tor
*/
virtual ~AutoOutputDevice();
/**
* @brief This method is used by our TDEBUGX macros to define if the
* current debug level set in the environment is enough to print the
* current debug message.
*
* If BOB_DEBUG is defined and has an integer value of 1, 2 or 3, this
* method will return 'true', if the value of 'i' is smaller or equal to
* the value collected from the environment. Otherwise, returns false.
*/
bool debug_level(unsigned int i);
/**
* @brief Forwards call to underlying OutputDevice
*/
virtual std::streamsize write(const char* s, std::streamsize n);
/**
* @brief Chooses the correct temporary directory to use, like this:
*
* - The environment variable TMPDIR, if it is defined. For security reasons
* this only happens if the program is not SUID or SGID enabled.
* - The directory /tmp.
*/
std::string tmpdir();
/**
* @brief Closes this base sink
*/
virtual void close();
/**
* @brief Returns the full path of a temporary file in tmpdir().
*
* @param extension The desired extension for the file
*/
std::string tmpfile(const std::string& extension=".hdf5");
private:
/**
* @}
*/
}
boost::shared_ptr<OutputDevice> m_device; ///< Who does the real job.
};
// standard streams
extern boost::iostreams::stream<AutoOutputDevice> debug;
extern boost::iostreams::stream<AutoOutputDevice> info;
extern boost::iostreams::stream<AutoOutputDevice> warn;
extern boost::iostreams::stream<AutoOutputDevice> error;
/**
* @brief This method is used by our TDEBUGX macros to define if the
* current debug level set in the environment is enough to print the
* current debug message.
*
* If BOB_DEBUG is defined and has an integer value of 1, 2 or 3, this
* method will return 'true', if the value of 'i' is smaller or equal to
* the value collected from the environment. Otherwise, returns false.
*/
bool debug_level(unsigned int i);
}
}}
//returns the current location where the message is being printed
#ifndef TLOCATION
......@@ -175,4 +145,4 @@ namespace bob {
#define TDEBUG3(v)
#endif
#endif /* BOB_CORE_LOGGING_H */
#endif /* BOB_CORE_LOGGING_API_H */
/**
* @author Andre Anjos <andre.anjos@idiap.ch>
* @date Mon 04 Aug 2014 13:17:07 CEST
*
* @brief C/C++-API for the logging module
*/
#ifndef BOB_CORE_LOGGING_H
#define BOB_CORE_LOGGING_H
#include <Python.h>
#include <bob.core/config.h>
#include <boost/shared_ptr.hpp>
#include <bob.core/_logging_api.h>
/* Define Module Name and Prefix for other Modules
Note: We cannot use BOB_EXT_* macros here, unfortunately */
#define BOB_CORE_LOGGING_PREFIX "bob.core"
#define BOB_CORE_LOGGING_FULL_NAME "bob.core._logging"
/*******************
* C API functions *
*******************/
/**************
* Versioning *
**************/
#define PyBobCoreLogging_APIVersion_NUM 0
#define PyBobCoreLogging_APIVersion_TYPE int
/*********************************
* Bindings for bob.core.logging *
*********************************/
#define PyBobCoreLogging_Debug_NUM 1
#define PyBobCoreLogging_Debug_RET boost::iostreams::stream<bob::core::AutoOutputDevice>&
#define PyBobCoreLogging_Debug_PROTO ()
#define PyBobCoreLogging_Info_NUM 2
#define PyBobCoreLogging_Info_RET boost::iostreams::stream<bob::core::AutoOutputDevice>&
#define PyBobCoreLogging_Info_PROTO ()
#define PyBobCoreLogging_Warn_NUM 3
#define PyBobCoreLogging_Warn_RET boost::iostreams::stream<bob::core::AutoOutputDevice>&
#define PyBobCoreLogging_Warn_PROTO ()
#define PyBobCoreLogging_Error_NUM 4
#define PyBobCoreLogging_Error_RET boost::iostreams::stream<bob::core::AutoOutputDevice>&
#define PyBobCoreLogging_Error_PROTO ()
/* Total number of C API pointers */
#define PyBobCoreLogging_API_pointers 5
#ifdef BOB_CORE_LOGGING_MODULE
/* This section is used when compiling `bob.core.logging' itself */
/**************
* Versioning *
**************/
extern int PyBobCoreLogging_APIVersion;
/*********************************
* Bindings for bob.core.logging *
*********************************/
PyBobCoreLogging_Debug_RET PyBobCoreLogging_Debug PyBobCoreLogging_Debug_PROTO;
PyBobCoreLogging_Info_RET PyBobCoreLogging_Info PyBobCoreLogging_Info_PROTO;
PyBobCoreLogging_Warn_RET PyBobCoreLogging_Warn PyBobCoreLogging_Warn_PROTO;
PyBobCoreLogging_Error_RET PyBobCoreLogging_Error PyBobCoreLogging_Error_PROTO;
#else
/* This section is used in modules that use `bob.core.logging's' C-API */
# if defined(NO_IMPORT_ARRAY)
extern void **PyBobCoreLogging_API;
# else
# if defined(PY_ARRAY_UNIQUE_SYMBOL)
void **PyBobCoreLogging_API;
# else
static void **PyBobCoreLogging_API=NULL;
# endif
# endif
/**************
* Versioning *
**************/
# define PyBobCoreLogging_APIVersion (*(PyBobCoreLogging_APIVersion_TYPE *)PyBobCoreLogging_API[PyBobCoreLogging_APIVersion_NUM])
/*********************************
* Bindings for bob.core.logging *
*********************************/
# define PyBobCoreLogging_Debug (*(PyBobCoreLogging_Debug_RET (*)PyBobCoreLogging_Debug_PROTO) PyBobCoreLogging_API[PyBobCoreLogging_Debug_NUM])
# define PyBobCoreLogging_Info (*(PyBobCoreLogging_Info_RET (*)PyBobCoreLogging_Info_PROTO) PyBobCoreLogging_API[PyBobCoreLogging_Info_NUM])
# define PyBobCoreLogging_Warn (*(PyBobCoreLogging_Warn_RET (*)PyBobCoreLogging_Warn_PROTO) PyBobCoreLogging_API[PyBobCoreLogging_Warn_NUM])
# define PyBobCoreLogging_Error (*(PyBobCoreLogging_Error_RET (*)PyBobCoreLogging_Error_PROTO) PyBobCoreLogging_API[PyBobCoreLogging_Error_NUM])
# if !defined(NO_IMPORT_ARRAY)
/**
* Returns -1 on error, 0 on success.
*/
static int import_bob_core_logging(void) {
PyObject *c_api_object;
PyObject *module;
module = PyImport_ImportModule(BOB_CORE_LOGGING_FULL_NAME);
if (module == NULL) return -1;
c_api_object = PyObject_GetAttrString(module, "_C_API");
if (c_api_object == NULL) {
Py_DECREF(module);
return -1;
}
# if PY_VERSION_HEX >= 0x02070000
if (PyCapsule_CheckExact(c_api_object)) {
PyBobCoreLogging_API = (void **)PyCapsule_GetPointer(c_api_object,
PyCapsule_GetName(c_api_object));
}
# else
if (PyCObject_Check(c_api_object)) {
PyBobCoreLogging_API = (void **)PyCObject_AsVoidPtr(c_api_object);
}
# endif
Py_DECREF(c_api_object);
Py_DECREF(module);
if (!PyBobCoreLogging_API) {
PyErr_SetString(PyExc_ImportError, "cannot find C/C++ API "
# if PY_VERSION_HEX >= 0x02070000
"capsule"
# else
"cobject"
# endif
" at `" BOB_CORE_LOGGING_FULL_NAME "._C_API'");
return -1;
}
/* Checks that the imported version matches the compiled version */
int imported_version = *(int*)PyBobCoreLogging_API[PyBobCoreLogging_APIVersion_NUM];
if (BOB_CORE_API_VERSION != imported_version) {
PyErr_Format(PyExc_ImportError, BOB_CORE_LOGGING_FULL_NAME " import error: you compiled against API version 0x%04x, but are now importing an API with version 0x%04x which is not compatible - check your Python runtime environment for errors", BOB_CORE_API_VERSION, imported_version);
return -1;
}
/* If you get to this point, all is good */
return 0;
}
# endif //!defined(NO_IMPORT_ARRAY)
#endif /* BOB_CORE_LOGGING_MODULE */
#endif /* BOB_CORE_LOGGING_H */
......@@ -336,7 +336,7 @@ typedef struct {
#else
/* This section is used in modules that use `blitz.array's' C-API */
/* This section is used in modules that use `bob.core.random's' C-API */
# if defined(NO_IMPORT_ARRAY)
extern void **PyBobCoreRandom_API;
......
......@@ -5,7 +5,9 @@
* @brief Bindings to re-inject C++ messages into the Python logging module
*/
#include <Python.h>
#define BOB_CORE_LOGGING_MODULE
#include <bob.core/logging.h>
#include <boost/shared_array.hpp>
#include <boost/make_shared.hpp>
#include <bob.core/config.h>
......@@ -18,7 +20,26 @@
static boost::iostreams::stream<bob::core::AutoOutputDevice> static_log("stdout");
#endif
#include "cpp/logging.h"
/**
* Free standing functions for the module's C-API
*/
int PyBobCoreLogging_APIVersion = BOB_CORE_API_VERSION;
boost::iostreams::stream<bob::core::AutoOutputDevice>& PyBobCoreLogging_Debug() {
return bob::core::debug;
}
boost::iostreams::stream<bob::core::AutoOutputDevice>& PyBobCoreLogging_Info() {
return bob::core::info;
}
boost::iostreams::stream<bob::core::AutoOutputDevice>& PyBobCoreLogging_Warn() {
return bob::core::warn;
}
boost::iostreams::stream<bob::core::AutoOutputDevice>& PyBobCoreLogging_Error() {
return bob::core::error;
}
/**
* Objects of this class are able to redirect the data injected into a
......@@ -512,8 +533,41 @@ static PyObject* create_module (void) {
auto m_ = make_safe(m);
/* register some constants */
if (PyModule_AddIntConstant(m, "__api_version__", BOB_CORE_API_VERSION) < 0) return 0;
if (PyModule_AddStringConstant(m, "__version__", BOB_EXT_MODULE_VERSION) < 0) return 0;
static void* PyBobCoreLogging_API[PyBobCoreLogging_API_pointers];
/* exhaustive list of C APIs */
PyBobCoreLogging_API[PyBobCoreLogging_APIVersion_NUM] = (void *)&PyBobCoreLogging_APIVersion;
/*********************************
* Bindings for bob.core.logging *
*********************************/
PyBobCoreLogging_API[PyBobCoreLogging_Debug_NUM] = (void *)PyBobCoreLogging_Debug;
PyBobCoreLogging_API[PyBobCoreLogging_Info_NUM] = (void *)PyBobCoreLogging_Info;
PyBobCoreLogging_API[PyBobCoreLogging_Warn_NUM] = (void *)PyBobCoreLogging_Warn;
PyBobCoreLogging_API[PyBobCoreLogging_Error_NUM] = (void *)PyBobCoreLogging_Error;
#if PY_VERSION_HEX >= 0x02070000
/* defines the PyCapsule */
PyObject* c_api_object = PyCapsule_New((void *)PyBobCoreLogging_API,
BOB_EXT_MODULE_PREFIX "." BOB_EXT_MODULE_NAME "._C_API", 0);
#else
PyObject* c_api_object = PyCObject_FromVoidPtr((void *)PyBobCoreLogging_API, 0);
#endif
if (c_api_object) PyModule_AddObject(m, "_C_API", c_api_object);
Py_INCREF(m);
return m;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment