Antispam fix
[forms.git] / src / F_Log.C
blobc39672d0e23329bedad330c7bea6e94373e60539
2  /*
3   *   Copyright (C) 2007, Harbour, All rights reserved.
4   */
6 #include <iostream>
7 #include <fstream>
8 #include <cstdarg>
9 #include <F_Log.H>
10 #include <cc++/thread.h>
12 using namespace F;
14 // env vars :
16 // FLOG_LEVEL="info"
17 // FLOG_PREFIX="myapp"
18 // FLOG_FILE="some_file"
19 // FLOG_DATE_FORMAT="%F %T" (in strftime format)
21 static log_level_t current_log_level_ = (log_level_t) -1;
22 static std::string log_prefix_; //!< ÐÒÅÆÉËÓ ÌÏÇ-ÓÏÏÂÝÅÎÉÑ
23 static std::string log_date_format_; //!< strftime-like ÆÏÒÍÁÔ log-ÄÁÔÙ
24 static std::streambuf *clog_buffer = 0; //!< ÕËÁÚÁÔÅÌØ ÎÁ ÏÒÉÇÉÎÁÌØÎÙÊ ÂÕÆÅÒ clog ÐÏÔÏËÁ
25 static std::ofstream *log_file_ = 0;
26 static char *log_msgbuf_ = 0;
27 static unsigned int log_msgbuf_size_ = 0;
28 ost::Mutex log_m;
30 namespace F {
31   void log(const char *location, log_level_t level);
34 #include <cc++/cmdoptns.h>
35 extern ost::CommandOption *f_app_cmd_options;
37 ost::CommandOptionArg logfile_option("logfile", 0, "\t\tsets log file",
38   false, &f_app_cmd_options);
39 ost::CommandOptionArg loglevel_option("loglevel", 0, "\t\tdefault log level, \'list\' for available",
40   false, &f_app_cmd_options);
41 //ost::CommandOptionArg syslog_class_option("syslogclass", 0,
42 //  "\tsets syslog class (facility)", false, &f_app_cmd_options);
44 static val_names_t log_level_names_[] = {
45  { DEBUG_LEVEL,     "debug"     },
46  { CHAT_LEVEL,      "chat"      },
47  { INFO_LEVEL,      "info"      },
48  { NOTICE_LEVEL,    "notice"    },
49  { WARN_LEVEL,      "warn"      },
50  { ERROR_LEVEL,     "error"     },
51  { ALERT_LEVEL,     "alert"     },
52  { CRITICAL_LEVEL,  "critical"  },
53  { FATAL_LEVEL,     "fatal"     }
56 // ÓÄÅÌÁÔØ ÛÁÂÌÏÎÏÍ
57 static log_level_t str2loglevel(const char *str)
59  for (unsigned int i = 0; i <
60   (sizeof(log_level_names_)/sizeof(val_names_t)); i++) {
61      if (!::strcmp(str, log_level_names_[i].name))
62        return (log_level_t)log_level_names_[i].val;
63  }
64  return (log_level_t) -1;
67 static const char *loglevel2str(log_level_t level)
69  if ((level < 0) || ((unsigned int)level >
70      (sizeof(log_level_names_)/sizeof(val_names_t))))
71        return 0;
72  return log_level_names_[level].name;
75 static void print_loglevels_help(const char *value, const char *from)
77  if (!strcmp(value, "list"))
78    std::cerr << std::endl << from << " value must be one of the :\n\n";
79  else
80    std::cerr << std::endl << "Invalid " << from << " value (\"" << value <<
81      "\") ! Must be one of the :\n\n";
82  std::cerr << " [ debug | chat | info | notice | warn | error | alert |"
83    " critical | fatal ]\n\n";
86 void F::log_level(log_level_t level)
88  log_m.enterMutex();
89  current_log_level_ = level;
90  log_m.leaveMutex();
93 void F::log_level(const char *lv)
95  log_m.enterMutex();
96  current_log_level_ = str2loglevel(lv);
97  log_m.leaveMutex();
98  if (current_log_level_ < 0) {
99   print_loglevels_help(lv, "log level option");
100   ::exit(-1);
104 void F::log_date_format(std::string &format)
106  log_m.enterMutex();
107  log_date_format_ = format;
108  log_m.leaveMutex();
111 void F::log_date_format(const char *format)
113  log_m.enterMutex();
114  log_date_format_ = format;
115  log_m.leaveMutex();
118 void F::log_prefix(const char *prefix)
120  log_m.enterMutex();
121  if (prefix)
122    log_prefix_ = prefix;
123  log_m.leaveMutex();
126 void F::log_msgbuf_size(unsigned int size)
128  log_m.enterMutex();
129  if (log_msgbuf_)
130    delete [] log_msgbuf_;
131  log_msgbuf_size_ = size;
132  log_msgbuf_ = new char[size];
133  log_m.leaveMutex();
136 void F::log(const char *location, const char *fmt, ...)
138  log_m.enterMutex();
139  ::va_list args;
140  ::va_start(args, fmt);
141  ::va_end(args);
142  ::vsnprintf(log_msgbuf_, log_msgbuf_size_, fmt, args);
143  log(location, DEFAULT_LOG_LEVEL);
146 void F::log(const char *location, log_level_t level, const char *fmt, ...)
148  log_m.enterMutex();
149  ::va_list args;
150  ::va_start(args, fmt);
151  ::va_end(args);
152  ::vsnprintf(log_msgbuf_, log_msgbuf_size_, fmt, args);
153  log(location, level);
156 void F::log_(const char *location, const char *buf)
158  log_m.enterMutex();
159  strcpy(log_msgbuf_, buf);
160  log(location, DEFAULT_LOG_LEVEL);
163 void F::log_(const char *location, log_level_t level, const char *buf)
165  log_m.enterMutex();
166  strcpy(log_msgbuf_, buf);
167  log(location, level);
170 void F::log_init(const char *prog_name)
172  log_m.enterMutex();
173  if (current_log_level_ < 0) { // not yet setted up
174   const char *log_level = ::getenv("FLOG_LEVEL");
175   if (log_level) {
176     // may be test for string correctness ?...
177     if ((current_log_level_ = str2loglevel(log_level)) < 0) {
178       print_loglevels_help(log_level, "$FLOG_LEVEL variable");
179       ::exit(-1);
180     }
181   } else
182          current_log_level_ = DEFAULT_LOG_LEVEL;
184  log_msgbuf_ = 0;
185  clog_buffer = 0;
186  log_file_ = 0;
187  log_prefix_ = prog_name;
188  log_m.leaveMutex();
189  log_date_format("%F %T");
190  log_msgbuf_size(10240U);
191  if (loglevel_option.numValue)
192    log_level(loglevel_option.values[0]);
193  if (logfile_option.numValue)
194    log_file(logfile_option.values[0]);
197 void F::log_file(const char *f)
199  log_m.enterMutex();
200  clog_buffer = std::clog.rdbuf();
201  log_file_ = new std::ofstream(f, std::ios::out | std::ios::app);
202  // check errors
203  if (!log_file_->good()) { // ÐÒÏÉÚÏÛÌÁ ÏÛÉÂËÁ
204   std::clog << "Error opening " << f << " logfile !\n";
205   delete log_file_;
206   log_file_ = 0;
207   clog_buffer = 0;
208  } else
209       std::clog.rdbuf(log_file_->rdbuf());
210  log_m.leaveMutex();
213 void F::log_final(void)
215  log_m.enterMutex();
216  if (clog_buffer)
217    std::clog.rdbuf(clog_buffer);
218  if (log_file_)
219    delete log_file_;
220  if (log_msgbuf_)
221    delete [] log_msgbuf_;
222  log_file_ = 0;
223  clog_buffer = 0;
224  log_msgbuf_size_ = 0;
225  log_msgbuf_ = 0;
226  log_m.leaveMutex();
229 //! ÅÓÌÉ ÎÅ ÚÁÄÁΠlogfile/loglevel ÕÓÅ ×ÙÄÁÅÔÓÑ × stderr
230 // ÅÓÌÉ ÞÅÇÏ ÚÁÄÁÎÏ - ÄÏÐÏÌÎÉÔÅÌØÎÏ ×ËÌÀÞÁÅÔÓÑ ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ ËÁÎÁÌ
232 // date [log_level] [prefix-pid:location] Message
235 #include <cc++/numbers.h>
236 #include <ctime>
238 void F::log(const char *location, log_level_t level)
240  // log_m.enterMutex(); we already locked
241  if (level >= current_log_level_) {
242    ost::Datetime date_(time(0));
243    std::clog << date_.strftime(log_date_format_.c_str()) << " [" <<
244     loglevel2str(level) << "] [" << log_prefix_ << "-" << getpid() << ":" <<
245     location << "] " << log_msgbuf_ << std::endl;
246 //   std::clog.flush();
247    // check errors
248    if (!std::clog.good()) { // ÐÒÏÉÚÏÛÌÁ ÏÛÉÂËÁ
249     // check if we writing to the stream in case of the closed stderr/stdout
250     if (log_file_) {
251       // print file name ...?
252       std::cerr << "Error writing to log file !\n";
253       std::cout << "Error writing to log file !\n";
254       delete log_file_;
255       log_file_ = 0;
256     } else { // ÐÏÓÌÅÄÎÉÊ ËÒÉË, ÐÒÏÝÅ ÚÁÓÔÒÅÌÉÔØÓÑ
257       std::cerr << "Can't write to clog stream !\n";
258       std::cout << "Can't write to clog stream !\n";
259     }
260     // cleanup log_file_ stream
261     if (clog_buffer) {
262       std::clog.rdbuf(clog_buffer);
263       clog_buffer = 0;
264     } // cleanup clog_buffer
265   } // error writing to log-stream
266  } // check current_log_level
267  log_m.leaveMutex();