วันจันทร์ที่ 28 พฤศจิกายน พ.ศ. 2554

xsyslog

/*
 * History
 * ===========================================================
 * Version     Date         Author        Description
 * ===========================================================
 *     0.1     10-MAR-11    Seree R.      Initial
 */
#ifndef _xsyslog_h_
#define _xsyslog_h_


#include <map>
#include <string>
#include <pthread.h>


/*
 * xsyslog is implemented by singleton pattern
 */
typedef std::map<std::string, int> str2int_t;


class xsyslog {
private:
  /*
   * Not allow new object by constructor, copy constructor, and also assignment operator.
   */
  xsyslog();
  xsyslog(const xsyslog&);
  xsyslog operator=(const xsyslog&);


public:
  /*
   * Create an instance of this object
   */
  static xsyslog *instance();
  virtual ~xsyslog();


public:
  /*
   * NAME: 
   *    write - write a message to system log
   * SYNOPSIS: 
   *    void write(const char *format, ...);
   *    static void write(const char *id, int facility, int level, const char *format, ...);
   * DESCRIPTION:
   *    The write() function sends a message to syslogd, which, 
   *    depending on the configuration of /etc/syslog.conf
   * RETURN VALUES:
   *    None
   * ERRORS:
   *    None
   * EXAMPLES:
   *    xsyslog *log = xsyslog::instance();
   *    log->id("my application");
   *    log->facility("LOG_LOCAL3");
   *    log->level("LOG_INFO");
   *    log->write("This is logged by pid(%d)", getpid());
   */
  void write(const char *format, ...);
  static void write(const char *id, int facility, int level, const char *format, ...);
  /*
   * NAME: 
   *    facility - get or set a facility of the message to system log
   * SYNOPSIS: 
   *    int  facility() const;               - get
   *    int  facility(int facility);         - set by integer
   *    int  facility(const char *facility); - set by string
   * DESCRIPTION:
   *    The facility() function gets or sets the facility of the message to system log
   * RETURN VALUES:
   *    The current facility or old facility before setting the new facility.
   *    See also facility in syslog(3C). Otherwise, -1 if facility string is to be set,
   *    it is not correct.
   * ERRORS:
   *    None
   * EXAMPLES:
   *    int old_facility = xsyslog::instance()->facility("LOG_LOCAL3");
   */
  int  facility() const { return facility_; }
  int  facility(int facility);   
  int  facility(const char *facility);
  /*
   * NAME: 
   *    level - get or set a level of the message to system log
   * SYNOPSIS: 
   *    int  level() const;            - get
   *    int  level(int level);         - set by integer
   *    int  level(const char *level); - set by string
   * DESCRIPTION:
   *    The level() function gets or sets the level of the message to system log
   * RETURN VALUES:
   *    The current level or old level before setting the new level.
   *    See also level in syslog(3C). Otherwise, -1 if level string is to be set,
   *    it is not correct.
   * ERRORS:
   *    None
   * EXAMPLES:
   *    int old_level = xsyslog::instance()->level("LOG_INFO");
   */
  int  level() const { return level_; }
  int  level(int level);
  int  level(const char *level);
  /*
   * NAME: 
   *    id - get or set an identifier of the message to system log
   * SYNOPSIS: 
   *    const char *id() const;          - get
   *    const char *id(const char *id);  - set
   * DESCRIPTION:
   *    The id() function gets or sets the id of the message to system log
   * RETURN VALUES:
   *    The current id or old id before setting the new id.
   *    See also id in syslog(3C). Otherwise, -1 if id string is to be set,
   *    it is not correct.
   * ERRORS:
   *    None
   * EXAMPLES:
   *    int old_level = xsyslog::instance()->id("my application");
   */
  const char *id() const;
  const char *id(const char *id);


private:
  std::string     id_;
  int             facility_;
  int             level_;
  pthread_mutex_t mutex_write_;
  pthread_mutex_t mutex_id_;
  pthread_mutex_t mutex_facility_;
  pthread_mutex_t mutex_level_;


private:
  static str2int_t  map_facility_;
  static str2int_t  map_level_;
  static xsyslog   *instance_;
};


#endif // _xsyslog_h_

///////////////////////////////////////
/*
 * History
 * ===========================================================
 * Version     Date         Author        Description
 * ===========================================================
 *     0.1     10-MAR-11    Seree R.      Initial
 */

#include "xsyslog.h"
#include <syslog.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

using std::map;
using std::string;

xsyslog   *xsyslog::instance_     = 0;
str2int_t  xsyslog::map_facility_ = str2int_t();
str2int_t  xsyslog::map_level_    = str2int_t();


xsyslog::xsyslog()
  : id_("xsyslog"), facility_(LOG_LOCAL0), level_(LOG_INFO)
{
  // mutex
  pthread_mutex_init(&mutex_write_, 0);
  pthread_mutex_init(&mutex_id_, 0);
  pthread_mutex_init(&mutex_facility_, 0);
  pthread_mutex_init(&mutex_level_, 0);
}

xsyslog::~xsyslog() {
  pthread_mutex_destroy(&mutex_write_);
  pthread_mutex_destroy(&mutex_id_);
  pthread_mutex_destroy(&mutex_facility_);
  pthread_mutex_destroy(&mutex_level_);
}
/*
Facility:
=========
     LOG_AUTH      The authorization system: login(1), su(1), getty(8), etc.
     LOG_CRON      The cron daemon: cron(8).
     LOG_DAEMON    System daemons, such as routed(8), that are not provided for explicitly by other facilities.
     LOG_KERN      Messages generated by the kernel.  These cannot be generated by any user processes.
     LOG_LPR       The line printer spooling system: lpr(1), lpc(8), lpd(8), etc.
     LOG_MAIL      The mail system.
     LOG_NEWS      The network news system.
     LOG_SYSLOG    Messages generated internally by syslogd(8).
     LOG_USER      Messages generated by random user processes.  This is the default facility identifier if none is specified.
     LOG_UUCP      The uucp system.
     LOG_LOCAL0    Reserved for local use.  Similarly for LOG_LOCAL1 through LOG_LOCAL7.

Level:
======
     LOG_EMERG     A panic condition.  This is normally broadcast to all users.
     LOG_ALERT     A condition that should be corrected immediately, such as a corrupted system database.
     LOG_CRIT      Critical conditions, e.g., hard device errors.
     LOG_ERR       Errors.
     LOG_WARNING   Warning messages.
     LOG_NOTICE    Conditions that are not error conditions, but should possibly be handled specially.
     LOG_INFO      Informational messages.
     LOG_DEBUG     Messages that contain information normally of use only when debugging a program.
*/

xsyslog *xsyslog::instance() {
  if(!instance_) {
    instance_ = new xsyslog();
    
    // setup facility
    map_facility_["LOG_AUTH"]     = LOG_AUTH;
    map_facility_["LOG_CRON"]     = LOG_CRON;
    map_facility_["LOG_DAEMON"]   = LOG_DAEMON;
    map_facility_["LOG_KERN"]     = LOG_KERN;
    map_facility_["LOG_LPR"]      = LOG_LPR;
    map_facility_["LOG_MAIL"]     = LOG_MAIL;
    map_facility_["LOG_NEWS"]     = LOG_NEWS;
    map_facility_["LOG_SYSLOG"]   = LOG_SYSLOG;
    map_facility_["LOG_USER"]     = LOG_USER;
    map_facility_["LOG_UUCP"]     = LOG_UUCP;
    map_facility_["LOG_LOCAL0"]   = LOG_LOCAL0;
    map_facility_["LOG_LOCAL1"]   = LOG_LOCAL1;
    map_facility_["LOG_LOCAL2"]   = LOG_LOCAL2;
    map_facility_["LOG_LOCAL3"]   = LOG_LOCAL3;
    map_facility_["LOG_LOCAL4"]   = LOG_LOCAL4;
    map_facility_["LOG_LOCAL5"]   = LOG_LOCAL5;
    map_facility_["LOG_LOCAL6"]   = LOG_LOCAL6;
    map_facility_["LOG_LOCAL7"]   = LOG_LOCAL7;

    // setup level
    map_level_["LOG_EMERG"]       = LOG_EMERG;
    map_level_["LOG_ALERT"]       = LOG_ALERT;
    map_level_["LOG_CRIT"]        = LOG_CRIT;
    map_level_["LOG_ERR"]         = LOG_ERR;
    map_level_["LOG_WARNING"]     = LOG_WARNING;
    map_level_["LOG_NOTICE"]      = LOG_NOTICE;
    map_level_["LOG_INFO"]        = LOG_INFO;
    map_level_["LOG_DEBUG"]       = LOG_DEBUG;
  }
  return instance_;
}

void xsyslog::write(const char *format, ...) {
  // format string to log
  char sz[1];
  va_list args;
  va_start(args, format);
  int len      = vsnprintf(sz, 1, format, args); 
  char *buffer = (char *)malloc(len+1);
  vsnprintf(buffer, len+1, format, args);
  va_end(args);

  // write the syslog now
  pthread_mutex_lock(&mutex_write_); 

  openlog(id_.c_str(), LOG_PID|LOG_NDELAY, facility_);
  syslog(level_, "%s", buffer);
  closelog();

  pthread_mutex_unlock(&mutex_write_); 
  // clean up memory
  free(buffer);
}

void xsyslog::write(const char *id, int facility, int level, const char *format, ...) {
  // format string to log
  va_list args;
  va_start(args, format);
  char sz[1];
  int len = vsnprintf(sz, 1, format, args); 
  char *buffer = (char *)malloc(len+1);
  vsnprintf(buffer, len+1, format, args);
  va_end(args);

  // write the syslog now
  openlog(id, LOG_PID|LOG_NDELAY, facility);
  syslog(level, "%s", buffer);
  closelog();
  free(buffer);
}

const char *xsyslog::id() const {
  return id_.c_str();
}

const char *xsyslog::id(const char *id) {
  pthread_mutex_lock(&mutex_id_); 
  
  string old_id = id_;
  id_ = id;
  
  pthread_mutex_unlock(&mutex_id_); 
  return old_id.c_str();
}

int xsyslog::facility(const char *facility) {
  str2int_t::iterator it = map_facility_.find(facility);
  if(it != map_facility_.end()) {
    pthread_mutex_lock(&mutex_facility_); 
    
    int old_facility = facility_;
    facility_ = (*it).second;
    
    pthread_mutex_unlock(&mutex_facility_); 
    return old_facility;
  }
  return -1;
}

int xsyslog::level(const char *level) {
  str2int_t::iterator it = map_level_.find(level);
  if(it != map_level_.end()) {
    pthread_mutex_lock(&mutex_level_); 
    
    int old_level = level_;
    level_ = (*it).second;
    
    pthread_mutex_unlock(&mutex_level_); 
    return old_level;
  }
  return -1;
}

int xsyslog::level(int level) { 
  pthread_mutex_lock(&mutex_level_); 
  
  int old_level = level_;
  level_ = level; 
  
  pthread_mutex_unlock(&mutex_level_);
  return old_level;
}

int xsyslog::facility(int facility) { 
  pthread_mutex_lock(&mutex_facility_); 
  
  int old_facility = facility_;
  facility_ = facility; 
  
  pthread_mutex_unlock(&mutex_facility_); 
  return old_facility;
}


/////////////////////////////////////////
#include "xsyslog.h"
#include <stdio.h>
#include <syslog.h>

/*
edit /etc/syslog.conf
add facility.level and path as needed
touch the path if it does not exist
*/
int main(int argc, char *argv[]) {
  if(argc != 5) {
    fprintf(stderr, "usage: %s id facility level log_message\n", argv[0]);
    fprintf(stderr, "example: %s \"myid\" \"LOG_LOCAL0\" \"LOG_INFO\" \"TEST MESSAGE\"\n", argv[0]);
    return 1;
  }
  xsyslog *log = xsyslog::instance();
//  log->id("EMT_TSA_3.5.2");
//  log->facility("LOG_LOCAL3");
//  log->level("LOG_INFO");
  log->id(argv[1]);
  log->facility(argv[2]);
  log->level(argv[3]);
  log->write("%s", argv[4]);
  
  xsyslog::write(argv[1], LOG_LOCAL0, LOG_NOTICE, "%s with static write function", argv[4]);
  return 0;
}