/* -*- c++ -*- */
/*
 * Copyright 2012-2013 Free Software Foundation, Inc.
 * 
 * This file is part of GNU Radio
 * 
 * GNU Radio 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 3, or (at your option)
 * any later version.
 * 
 * GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street,
 * Boston, MA 02110-1301, USA.
 */

/*******************************************************************************
* Author: Mark Plett
* Description:
*   The gr_logger module wraps the log4cpp library for logging in gnuradio
*******************************************************************************/

#ifndef INCLUDED_GR_LOGGER_H
#define INCLUDED_GR_LOGGER_H

/*!
* \file gr_logger.h
* \ingroup logging
* \brief GNURADIO logging wrapper for log4cpp library (C++ port of log4j)
*
*/

#include <gr_runtime_api.h>
#include <assert.h>
#include <iostream>
#include <time.h>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>

#ifdef ENABLE_GR_LOG

// We have three configurations... first logging to stdout/stderr
#ifndef HAVE_LOG4CPP
//#warning GR logging Enabled and using std::cout

typedef std::string gr_logger_ptr;

#define GR_LOG_DECLARE_LOGPTR(logger)
#define GR_LOG_ASSIGN_LOGPTR(logger,name)
#define GR_CONFIG_LOGGER(config)
#define GR_CONFIG_AND_WATCH_LOGGER(config,period)
#define GR_LOG_GETLOGGER(logger, name) 
#define GR_SET_LEVEL(name, level)
#define GR_LOG_SET_LEVEL(logger, level) 
#define GR_GET_LEVEL(name, level)
#define GR_LOG_GET_LEVEL(logger, level)
#define GR_ADD_CONSOLE_APPENDER(logger,target,pattern)
#define GR_LOG_ADD_CONSOLE_APPENDER(logger,target,pattern)
#define GR_ADD_FILE_APPENDER(name,filename,append,pattern)
#define GR_LOG_ADD_FILE_APPENDER(logger,filename,append,pattern)
#define GR_ADD_ROLLINGFILE_APPENDER(name,filename,filesize,bkup_index,append,mode,pattern)
#define GR_LOG_ADD_ROLLINGFILE_APPENDER(logger,filename,filesize,bkup_index,append,mode,pattern)
#define GR_GET_LOGGER_NAMES(names)
#define GR_RESET_CONFIGURATION()
#define GR_DEBUG(name, msg) std::cout<<"DEBUG: "<<msg<<std::endl
#define GR_INFO(name, msg) std::cout<<"INFO: "<<msg<<std::endl
#define GR_NOTICE(name, msg) std::cout<<"NOTICE: "<<msg<<std::endl
#define GR_WARN(name, msg) std::cerr<<"WARN: "<<msg<<std::endl
#define GR_ERROR(name, msg) std::cerr<<"ERROR: "<<msg<<std::endl
#define GR_ALERT(name, msg) std::cerr<<"ERROR: "<<msg<<std::endl
#define GR_CRIT(name, msg) std::cerr<<"ERROR: "<<msg<<std::endl
#define GR_FATAL(name, msg) std::cerr<<"FATAL: "<<msg<<std::endl
#define GR_EMERG(name, msg) std::cerr<<"EMERG: "<<msg<<std::endl
#define GR_ERRORIF(name, cond, msg) {if((cond)) std::cerr<<"ERROR: "<<msg<<std::endl;}
#define GR_ASSERT(name, cond, msg) {if(!(cond)) std::cerr<<"FATAL: "<<msg<<std::endl; assert(cond);}
#define GR_LOG_DEBUG(logger, msg) std::cout<<"DEBUG: "<<msg<<std::endl
#define GR_LOG_INFO(logger, msg) std::cout<<"INFO: "<<msg<<std::endl
#define GR_LOG_NOTICE(logger, msg) std::cout<<"NOTICE: "<<msg<<std::endl
#define GR_LOG_WARN(logger, msg) std::cerr<<"WARN: "<<msg<<std::endl
#define GR_LOG_ERROR(logger, msg) std::cerr<<"ERROR: "<<msg<<std::endl
#define GR_LOG_ALERT(logger, msg) std::cerr<<"ALERT: "<<msg<<std::endl
#define GR_LOG_CRIT(logger, msg) std::cerr<<"CRIT: "<<msg<<std::endl
#define GR_LOG_FATAL(logger, msg) std::cerr<<"FATAL: "<<msg<<std::endl
#define GR_LOG_EMERG(logger, msg) std::cerr<<"EMERG: "<<msg<<std::endl
#define GR_LOG_ERRORIF(logger, cond, msg) {\
  if((cond)) std::cerr<<"ERROR: "<<msg<<std::endl;}
#define GR_LOG_ASSERT(logger, cond, msg) {\
  if(!(cond)) {std::cerr<<"FATAL: "<<msg<<std::endl; assert(cond);};}

#else /* HAVE_LOG4CPP */
// Second configuration...logging to log4cpp

#include <log4cpp/Category.hh>
#include <log4cpp/PropertyConfigurator.hh>
#include <log4cpp/FileAppender.hh>
#include <log4cpp/RollingFileAppender.hh>
#include <log4cpp/OstreamAppender.hh>
#include <log4cpp/PatternLayout.hh>

/*!
 * \brief GR_LOG macros
 * \ingroup logging
 *
 * These macros wrap the standard LOG4CPP_LEVEL macros.  The availablie macros
 * are:
 *  GR_LOG_DEBUG
 *  GR_LOG_INFO
 *  GR_LOG_WARN
 *  GR_LOG_TRACE
 *  GR_LOG_ERROR
 *  GR_LOG_ALERT
 *  GR_LOG_CRIT
 *  GR_LOG_FATAL
 *  GR_LOG_EMERG
 */
typedef log4cpp::Category* gr_logger_ptr;

/* Macros for Programmatic Configuration */
#define GR_LOG_DECLARE_LOGPTR(logger) \
  gr_logger_ptr logger;

#define GR_LOG_ASSIGN_LOGPTR(logger,name) \
  logger = logger_get_logger(name);

#define GR_CONFIG_LOGGER(config)	\
  logger_config::load_config(config)

#define GR_CONFIG_AND_WATCH_LOGGER(config,period)	\
  logger_config::load_config(config,period)

#define GR_LOG_GETLOGGER(logger, name) \
  gr_logger_ptr logger = logger_get_logger(name);

#define GR_SET_LEVEL(name, level){ \
  gr_logger_ptr logger = logger_get_logger(name);\
  logger_set_level(logger,level);}

#define GR_LOG_SET_LEVEL(logger, level) \
  logger_set_level(logger, level);

#define GR_GET_LEVEL(name, level){ \
  gr_logger_ptr logger = logger_get_logger(name);\
  logger_get_level(logger,level);}

#define GR_LOG_GET_LEVEL(logger, level) \
  logger_get_level(logger,level);

#define GR_ADD_CONSOLE_APPENDER(name,target,pattern){\
  gr_logger_ptr logger = logger_get_logger(name);\
  logger_add_console_appender(logger,target,pattern);}

#define GR_LOG_ADD_CONSOLE_APPENDER(logger,target,pattern){\
  logger_add_console_appender(logger,target,pattern);}

#define GR_ADD_FILE_APPENDER(name,filename,append,pattern){\
  gr_logger_ptr logger = logger_get_logger(name);\
  logger_add_file_appender(logger,filename,append,pattern);}

#define GR_LOG_ADD_FILE_APPENDER(logger,filename,append,pattern){\
  logger_add_file_appender(logger,filename,append,pattern);}

#define GR_ADD_ROLLINGFILE_APPENDER(name,filename,filesize,bkup_index,append,mode,pattern){\
  gr_logger_ptr logger = logger_get_logger(name);\
  logger_add_rollingfile_appender(logger,filename,filesize,bkup_index,append,mode,pattern);}

#define GR_LOG_ADD_ROLLINGFILE_APPENDER(logger,filename,filesize,bkup_index,append,mode,pattern){\
  logger_add_rollingfile_appender(logger,filename,filesize,bkup_index,append,mode,pattern);}

#define GR_GET_LOGGER_NAMES(names){ \
  names = logger_get_logger_names();}

#define GR_RESET_CONFIGURATION(){ \
  logger_config::reset_config();}

/* Logger name referenced macros */
#define GR_DEBUG(name, msg) { \
  gr_logger_ptr logger = logger_get_logger(name);\
  *logger<< log4cpp::Priority::DEBUG << msg << log4cpp::eol;}

#define GR_INFO(name, msg) { \
  gr_logger_ptr logger = logger_get_logger(name);\
  *logger<< log4cpp::Priority::INFO << msg << log4cpp::eol;}

#define GR_NOTICE(name, msg) { \
  gr_logger_ptr logger = logger_get_logger(name);\
  *logger << log4cpp::Priority::NOTICE << msg;}

#define GR_WARN(name, msg) { \
  gr_logger_ptr logger = logger_get_logger(name);\
  *logger<< log4cpp::Priority::WARN << msg << log4cpp::eol;}

#define GR_ERROR(name, msg) { \
  gr_logger_ptr logger = logger_get_logger(name);\
  *logger<< log4cpp::Priority::ERROR << msg << log4cpp::eol;}

#define GR_CRIT(name, msg) { \
  gr_logger_ptr logger = logger_get_logger(name);\
  *logger<< log4cpp::Priority::CRIT << msg << log4cpp::eol;}

#define GR_ALERT(name, msg) { \
  gr_logger_ptr logger = logger_get_logger(name);\
  *logger<< log4cpp::Priority::ALERT << msg << log4cpp::eol;}

#define GR_FATAL(name, msg) { \
  gr_logger_ptr logger = logger_get_logger(name);\
  *logger<< log4cpp::Priority::FATAL << msg << log4cpp::eol;}

#define GR_EMERG(name, msg) { \
  gr_logger_ptr logger = logger_get_logger(name);\
  *logger<< log4cpp::Priority::EMERG << msg << log4cpp::eol;}

#define GR_ERRORIF(name, cond, msg) { \
if((cond)){\
  gr_logger_ptr logger = logger_get_logger(name);\
  *logger<< log4cpp::Priority::ERROR << msg << log4cpp::eol;};\
};

#define GR_ASSERT(name, cond, msg) { \
if(!(cond)){\
    gr_logger_ptr logger = logger_get_logger(name);\
    *logger<< log4cpp::Priority::EMERG << msg << log4cpp::eol;};\
    assert(0);\
};

/* LoggerPtr Referenced Macros */
#define GR_LOG_DEBUG(logger, msg) { \
  *logger << log4cpp::Priority::DEBUG << msg << log4cpp::eol;}

#define GR_LOG_INFO(logger, msg) { \
  *logger << log4cpp::Priority::INFO << msg << log4cpp::eol;}

#define GR_LOG_NOTICE(logger, msg) { \
  *logger << log4cpp::Priority::NOTICE << msg << log4cpp::eol;}

#define GR_LOG_WARN(logger, msg) { \
  *logger << log4cpp::Priority::WARN << msg << log4cpp::eol;}

#define GR_LOG_ERROR(logger, msg) { \
  *logger << log4cpp::Priority::ERROR << msg << log4cpp::eol;}

#define GR_LOG_CRIT(logger, msg) { \
  *logger << log4cpp::Priority::CRIT << msg << log4cpp::eol;}

#define GR_LOG_ALERT(logger, msg) { \
  *logger << log4cpp::Priority::ALERT << msg << log4cpp::eol;}

#define GR_LOG_FATAL(logger, msg) { \
  *logger << log4cpp::Priority::FATAL << msg << log4cpp::eol;}

#define GR_LOG_EMERG(logger, msg) { \
  *logger << log4cpp::Priority::EMERG << msg << log4cpp::eol;}

#define GR_LOG_ERRORIF(logger,cond, msg) { \
if((cond)){\
    *logger<< log4cpp::Priority::ERROR << msg << log4cpp::eol;};\
};

#define GR_LOG_ASSERT(logger, cond, msg) { \
if(!(cond)){\
    *logger<< log4cpp::Priority::EMERG << msg << log4cpp::eol;\
    assert(0);};\
};

/*!
 * \brief Class to control configuration of logger.  
 * This is a singleton that cna launch a thread to wathc a config file for changes
 * \ingroup logging
 */
class logger_config {
private:
  /*! \brief filename of logger config file */
  std::string filename;
  /*! \brief Period (seconds) over which watcher thread checks config file for changes */
  unsigned int watch_period;
  /*! \brief Pointer to watch thread for config file changes */
  boost::thread *watch_thread;

  /*! \brief Watcher thread method 
   * /param filename Name of configuration file
   * /param watch_period Seconds between checks for changes in config file
   */
  static void watch_file(std::string filename,unsigned int watch_period);

  logger_config(){};  //!< Constructor
  logger_config(logger_config const&);  //!<Copy constructor
  void operator=(logger_config const&);  //!<Assignment Operator

  /*! \brief destrcutor stops watch thread before exits */
  ~logger_config(){ 
     stop_watch();
  };

  /*! \brief Instance getter for singleton.  Only used by class. */
  static logger_config& get_instance(void);

public:
  /*! \brief Getter for config filename */
  static std::string get_filename();
  /*! \brief Getter for watch period */
  static unsigned int get_watch_period();
  /*! \brief Method to load configuration
   * /param filename Name of configuration file
   * /param watch_period Seconds between checks for changes in config file
   */
  static void load_config(std::string filename,unsigned int watch_period=0);
  /*! \brief Method to stop watcher thread */
  static void stop_watch();
  /*! \brief method to reset logger configuration */
  static void reset_config(void);
};

/*!
 * \brief Retrieve a pointer to a logger by name
 *
 * Retrives a logger pointer
 * \p name.
 *
 * \param name Name of the logger for which a pointer is requested
 */
GR_RUNTIME_API gr_logger_ptr logger_get_logger(std::string name);

/*!
 * \brief Load logger's configuration file.
 *
 * Initialize the GNU Radio logger by loading the configuration file
 * \p config_filename.
 *
 * \param config_filename The configuration file. Set to "" for the
 *        basic logger that outputs to the console.
 */
GR_RUNTIME_API void logger_load_config(const std::string &config_filename="");

/*!
 * \brief Reset logger's configuration file.
 *
 * Remove all appenders from loggers
 */
GR_RUNTIME_API void logger_reset_config(void);

GR_RUNTIME_API void logger_load_config_and_watch(const std::string &config_filename,
						 unsigned int watch_period);


/*!
 * \brief Set the logger's output level.
 *
 * Sets the level of the logger. This takes a string that is
 * translated to the standard levels and can be (case insensitive):
 *
 * \li off , notset
 * \li debug
 * \li info
 * \li notice
 * \li warn
 * \li error
 * \li crit
 * \li alert
 * \li fatal
 * \li emerg
 *
 * \param logger the logger to set the level of.
 * \param level  string to set the level to.
 */
GR_RUNTIME_API void logger_set_level(gr_logger_ptr logger, const std::string &level);

/*!
 * \brief Set the logger's output level.
 *
 * Sets the level of the logger. This takes the actual Log4cpp::Priority
 * data type, which can be:
 *
 * \li log4cpp::Priority::NOTSET
 * \li log4cpp::Priority::DEBUG
 * \li log4cpp::Priority::INFO
 * \li log4cpp::Priority::NOTICE
 * \li log4cpp::Priority::WARN
 * \li log4cpp::Priority::ERROR
 * \li log4cpp::Priority::CRIT
 * \li log4cpp::Priority::ALERT
 * \li log4cpp::Priority::FATAL
 * \li log4cpp::Priority::EMERG
 *
 * \param logger the logger to set the level of.
 * \param level  new logger level of type Log4cpp::Priority
 */
GR_RUNTIME_API void logger_set_level(gr_logger_ptr logger, log4cpp::Priority::Value level);


/*!
 * \brief Get the logger's output level.
 *
 * Gets the level of the logger. This returns a string that
 * corresponds to the standard levels and can be (case insensitive):
 *
 * \li notset
 * \li debug
 * \li info
 * \li notice
 * \li warn
 * \li error
 * \li crit
 * \li alert
 * \li fatal
 * \li emerg
 *
 * \param logger the logger to get the level of.
 * \param level  string to get the level into.
 */
GR_RUNTIME_API void logger_get_level(gr_logger_ptr logger, std::string &level);

/*!
 * \brief Get the logger's output level.
 *
 * Gets the level of the logger. This returns the actual Log4cpp::Level
 * data type, which can be:
 *
 * \li log4cpp::Priority::NOTSET
 * \li log4cpp::Priority::DEBUG
 * \li log4cpp::Priority::INFO
 * \li log4cpp::Priority::NOTICE
 * \li log4cpp::Priority::WARN
 * \li log4cpp::Priority::ERROR
 * \li log4cpp::Priority::CRIT
 * \li log4cpp::Priority::ALERT
 * \li log4cpp::Priority::FATAL
 * \li log4cpp::Priority::EMERG
 *
 * \param logger the logger to get the level of.
 * \param level of the logger.
 */
GR_RUNTIME_API void logger_get_level(gr_logger_ptr logger, log4cpp::Priority::Value &level);

/*!
 * \brief Add console appender to a given logger
 *
 * Add console appender to a given logger
 *
 * \param logger Logger to which appender will be added
 * \param target Std target to write 'cout' or 'cerr' (default is cout)
 * \param pattern Formating pattern for log messages
 */
GR_RUNTIME_API void logger_add_console_appender(gr_logger_ptr logger,std::string target,std::string pattern);

/*!
 * \brief Add file appender to a given logger
 *
 * Add file appender to a given logger
 *
 * \param logger Logger to which appender will be added
 * \param filename File to which log will be written
 * \param append Overwrite or append to log file
 * \param pattern Formating pattern for log messages
 */
GR_RUNTIME_API void logger_add_file_appender(gr_logger_ptr logger,std::string filename,bool append,std::string pattern);

/*!
 * \brief Add rolling file appender to a given logger
 *
 * Add rolling file appender to a given logger
 *
 * \param logger Logger to which appender will be added
 * \param filename File to which log will be written
 * \param filesize Sizez of files to write
 * \param bkup_index Number of files to write
 * \param append Overwrite or append to log file
 * \param mode Permissions to set on log file
 * \param pattern Formating pattern for log messages
 */
GR_RUNTIME_API void logger_add_rollingfile_appender(gr_logger_ptr logger,std::string filename,
                    size_t filesize,int bkup_index,bool append,mode_t mode,std::string pattern);


/*!
 * \brief Add rolling file appender to a given logger
 *
 * Add rolling file appender to a given logger
 *
 * \return vector of string names of loggers 
 */
GR_RUNTIME_API std::vector<std::string> logger_get_logger_names(void);

#endif /* HAVE_LOG4CPP */


// If Logger disable do nothing
#else /* ENABLE_GR_LOG */

typedef void* gr_logger_ptr;

#define GR_LOG_DECLARE_LOGPTR(logger)
#define GR_LOG_ASSIGN_LOGPTR(logger,name)
#define GR_CONFIG_LOGGER(config)
#define GR_CONFIG_AND_WATCH_LOGGER(config,period)
#define GR_LOG_GETLOGGER(logger, name) 
#define GR_SET_LEVEL(name, level)
#define GR_LOG_SET_LEVEL(logger, level) 
#define GR_GET_LEVEL(name, level)
#define GR_LOG_GET_LEVEL(logger, level)
#define GR_ADD_CONSOLE_APPENDER(logger,target,pattern)
#define GR_LOG_ADD_CONSOLE_APPENDER(logger,target,pattern)
#define GR_ADD_FILE_APPENDER(name,filename,append,pattern)
#define GR_LOG_ADD_FILE_APPENDER(logger,filename,append,pattern)
#define GR_ADD_ROLLINGFILE_APPENDER(name,filename,filesize,bkup_index,append,mode,pattern)
#define GR_LOG_ADD_ROLLINGFILE_APPENDER(logger,filename,filesize,bkup_index,append,mode,pattern)
#define GR_GET_LOGGER_NAMES(names)
#define GR_RESET_CONFIGURATION()
#define GR_DEBUG(name, msg)
#define GR_INFO(name, msg)
#define GR_NOTICE(name, msg)
#define GR_WARN(name, msg)
#define GR_ERROR(name, msg)
#define GR_ALERT(name, msg)
#define GR_CRIT(name, msg)
#define GR_FATAL(name, msg)
#define GR_EMERG(name, msg)
#define GR_ERRORIF(name, cond, msg)
#define GR_ASSERT(name, cond, msg)
#define GR_LOG_DEBUG(logger, msg)
#define GR_LOG_INFO(logger, msg)
#define GR_LOG_NOTICE(logger, msg)
#define GR_LOG_WARN(logger, msg)
#define GR_LOG_ERROR(logger, msg)
#define GR_LOG_ALERT(logger, msg)
#define GR_LOG_CRIT(logger, msg)
#define GR_LOG_FATAL(logger, msg)
#define GR_LOG_EMERG(logger, msg)
#define GR_LOG_ERRORIF(logger, cond, msg)
#define GR_LOG_ASSERT(logger, cond, msg)

#endif /* ENABLE_GR_LOG */

// Even if logger is disabled we'll need for methods below to exist in python.
// The macros these call will be disabled if ENABLE_GR_LOG is undefined

/********************* Start  Classes and Methods for Python ******************/
/*!
 * \brief Logger class for referencing loggers in python.  Not needed in C++ (use macros)
 * Wraps and manipulates loggers for python as python has no macros
 * \ingroup logging
 *
 */
class gr_logger
{
 private:
  /*! \brief logger pointer to logger associated wiith this wrapper class */
  gr_logger_ptr d_logger;
 public:
  /*!
   * \brief contructor Provide name of logger to associate with this class
   * \param logger_name Name of logger associated with class
   */
  gr_logger(std::string logger_name) {
    GR_LOG_ASSIGN_LOGPTR(d_logger,logger_name);
  };

  /*! \brief Destructor */
  ~gr_logger(){;};

  // Wrappers for logging macros
  /*! \brief inline function, wrapper to set the logger level */
  void set_level(std::string level){GR_LOG_SET_LEVEL(d_logger,level);}

  /*! \brief inline function, wrapper to get the logger level */
  void get_level(std::string &level){GR_LOG_GET_LEVEL(d_logger,level);}

  /*! \brief inline function, wrapper for LOG4CPP_DEBUG for DEBUG message */
  void debug(std::string msg){GR_LOG_DEBUG(d_logger,msg);};

  /*! \brief inline function, wrapper for LOG4CPP_INFO for INFO message */
  void info(std::string msg){GR_LOG_INFO(d_logger,msg);};

  /*! \brief inline function, wrapper for NOTICE message */
  void notice(std::string msg){GR_LOG_NOTICE(d_logger,msg);};

  /*! \brief inline function, wrapper for LOG4CPP_WARN for WARN message */
  void warn(std::string msg){GR_LOG_WARN(d_logger,msg);};

  /*! \brief inline function, wrapper for LOG4CPP_ERROR for ERROR message */
  void error(std::string msg){GR_LOG_ERROR(d_logger,msg);};

  /*! \brief inline function, wrapper for NOTICE message */
  void crit(std::string msg){GR_LOG_CRIT(d_logger,msg);};

  /*! \brief inline function, wrapper for ALERT message */
  void alert(std::string msg){GR_LOG_ALERT(d_logger,msg);};

  /*! \brief inline function, wrapper for FATAL message */
  void fatal(std::string msg){GR_LOG_FATAL(d_logger,msg);};

  /*! \brief inline function, wrapper for EMERG message */
  void emerg(std::string msg){GR_LOG_EMERG(d_logger,msg);};

  /*! \brief inline function, wrapper for LOG4CPP_ASSERT for conditional ERROR message */
  void errorIF(bool cond,std::string msg){GR_LOG_ERRORIF(d_logger,cond,msg);};

  /*! \brief inline function, wrapper for LOG4CPP_ASSERT for conditional ERROR message */
  void log_assert(bool cond,std::string msg){GR_LOG_ASSERT(d_logger,cond,msg);};

  /*! \brief inline function, Method to add console appender to logger */
  void add_console_appender(std::string target,std::string pattern){
     GR_LOG_ADD_CONSOLE_APPENDER(d_logger,target,pattern);
  };

  /*! \brief inline function, Method to add file appender to logger */
  void add_file_appender(std::string filename,bool append,std::string pattern){
     GR_LOG_ADD_FILE_APPENDER(d_logger,filename,append,pattern);
  };

  /*! \brief inline function, Method to add rolling file appender to logger */
  void add_rollingfile_appender(std::string filename,size_t filesize,
                int bkup_index,bool append,mode_t mode,std::string pattern){
     GR_LOG_ADD_ROLLINGFILE_APPENDER(d_logger,filename,filesize,
                bkup_index,append,mode,pattern);
  };
};

/**************** Start Configuration Class and Methods for Python ************/
/*!
 * \brief Function to call configuration macro from python.  
 *        Note: Configuration is only updated if filename or watch_period has changed.
 * \param config_filename  Name of configuration file
 * \param watch_period Seconds to wait between checking for changes in conf file.
 *        Watch_period defaults to 0 in which case the file is not watched for changes
 */
GR_RUNTIME_API void gr_logger_config(const std::string config_filename, unsigned int watch_period = 0);
/*!
 * \brief Function to return logger names to python
 * \return Vector of name strings
 *
 */
GR_RUNTIME_API std::vector<std::string> gr_logger_get_logger_names(void);
/*!
 * \brief Function to reset logger configuration from python
 * 
 */
GR_RUNTIME_API void gr_logger_reset_config(void);

#endif /* INCLUDED_GR_LOGGER_H */