3 * Copyright (C) 2007, Harbour, All rights reserved.
10 #include <cc++/thread.h>
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;
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" }
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;
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))))
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";
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)
89 current_log_level_ = level;
93 void F::log_level(const char *lv)
96 current_log_level_ = str2loglevel(lv);
98 if (current_log_level_ < 0) {
99 print_loglevels_help(lv, "log level option");
104 void F::log_date_format(std::string &format)
107 log_date_format_ = format;
111 void F::log_date_format(const char *format)
114 log_date_format_ = format;
118 void F::log_prefix(const char *prefix)
122 log_prefix_ = prefix;
126 void F::log_msgbuf_size(unsigned int size)
130 delete [] log_msgbuf_;
131 log_msgbuf_size_ = size;
132 log_msgbuf_ = new char[size];
136 void F::log(const char *location, const char *fmt, ...)
140 ::va_start(args, fmt);
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, ...)
150 ::va_start(args, fmt);
152 ::vsnprintf(log_msgbuf_, log_msgbuf_size_, fmt, args);
153 log(location, level);
156 void F::log_(const char *location, const char *buf)
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)
166 strcpy(log_msgbuf_, buf);
167 log(location, level);
170 void F::log_init(const char *prog_name)
173 if (current_log_level_ < 0) { // not yet setted up
174 const char *log_level = ::getenv("FLOG_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");
182 current_log_level_ = DEFAULT_LOG_LEVEL;
187 log_prefix_ = prog_name;
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)
200 clog_buffer = std::clog.rdbuf();
201 log_file_ = new std::ofstream(f, std::ios::out | std::ios::app);
203 if (!log_file_->good()) { // ÐÒÏÉÚÏÛÌÁ ÏÛÉÂËÁ
204 std::clog << "Error opening " << f << " logfile !\n";
209 std::clog.rdbuf(log_file_->rdbuf());
213 void F::log_final(void)
217 std::clog.rdbuf(clog_buffer);
221 delete [] log_msgbuf_;
224 log_msgbuf_size_ = 0;
229 //! ÅÓÌÉ ÎÅ ÚÁÄÁÎ logfile/loglevel ÕÓÅ ×ÙÄÁÅÔÓÑ × stderr
230 // ÅÓÌÉ ÞÅÇÏ ÚÁÄÁÎÏ - ÄÏÐÏÌÎÉÔÅÌØÎÏ ×ËÌÀÞÁÅÔÓÑ ÓÏÏÔ×ÅÔÓÔ×ÕÀÝÉÊ ËÁÎÁÌ
232 // date [log_level] [prefix-pid:location] Message
235 #include <cc++/numbers.h>
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();
248 if (!std::clog.good()) { // ÐÒÏÉÚÏÛÌÁ ÏÛÉÂËÁ
249 // check if we writing to the stream in case of the closed stderr/stdout
251 // print file name ...?
252 std::cerr << "Error writing to log file !\n";
253 std::cout << "Error writing to log file !\n";
256 } else { // ÐÏÓÌÅÄÎÉÊ ËÒÉË, ÐÒÏÝÅ ÚÁÓÔÒÅÌÉÔØÓÑ
257 std::cerr << "Can't write to clog stream !\n";
258 std::cout << "Can't write to clog stream !\n";
260 // cleanup log_file_ stream
262 std::clog.rdbuf(clog_buffer);
264 } // cleanup clog_buffer
265 } // error writing to log-stream
266 } // check current_log_level