00001
00012
00013
00014
00015
00016
00017 #ifndef Logger_cpp
00018 #define Logger_cpp
00019
00020 #include <cppunit/ui/text/TestRunner.h>
00021 #include <cppunit/TextOutputter.h>
00022 #include <cppunit/extensions/TestFactoryRegistry.h>
00023 #include <cppunit/extensions/HelperMacros.h>
00024 #include <cppunit/TestAssert.h>
00025
00026 #include <string>
00027 #include <map>
00028 #include <iostream>
00029 #include <cstdlib>
00030
00031 #include <coil/Logger.h>
00032 #include <coil/Task.h>
00033 #include <coil/TimeMeasure.h>
00034 #include <coil/stringutil.h>
00035 #include <coil/Time.h>
00036 #include <coil/Properties.h>
00037
00038 #include <coil/Mutex.h>
00039 #include <coil/Guard.h>
00040
00041 namespace coil
00042 {
00043 };
00044
00049 namespace Logger
00050 {
00051 class LogCreator
00052 : public coil::Task
00053 {
00054 public:
00055 LogCreator(const char* name, std::basic_streambuf<char>* streambuf)
00056 : m_name(name),
00057 m_out(streambuf)
00058
00059 {
00060 }
00061
00062 virtual int svc()
00063 {
00064 coil::TimeMeasure tm;
00065 for (int i(0); i < 100; ++i)
00066 {
00067 double r(rand() / (double)RAND_MAX * 100.0);
00068 tm.tick();
00069 {
00070 coil::Guard<coil::Mutex> guard(m_mutex);
00071 m_out << coil::sprintf("%s %03d %6.2f", m_name.c_str(), i, r) << std::endl;
00072 }
00073 tm.tack();
00074 coil::usleep((int)r);
00075 }
00076
00077 #if 0
00078 double max, min, mean, stddev;
00079 tm.getStatistics(max, min, mean, stddev);
00080 std::cout << m_name << std::endl;
00081 printf("max : %04.2f [us]\n", max * 1000000);
00082 printf("min : %04.2f [us]\n", min * 1000000);
00083 printf("mean : %04.2f [us]\n", mean * 1000000);
00084 printf("stddev: %04.2f [us]\n", stddev * 1000000);
00085 #endif
00086 return 0;
00087 }
00088
00089 private:
00090 std::string m_name;
00091 std::basic_ostream<char> m_out;
00092
00093 public:
00094 static coil::Mutex m_mutex;
00095 };
00096 coil::Mutex LogCreator::m_mutex;
00097
00098 enum LogLevel
00099 {
00100 SILENT_LEVEL,
00101 INFO_LEVEL,
00102 ERROR_LEVEL,
00103 TRACE_LEVEL,
00104 PARANOID_LEVEL
00105 };
00106
00107 class LogOut
00108 : public coil::LogStream
00109 {
00110
00111
00112 public:
00113 LogOut(::coil::LogStream::streambuf_type* streambuf)
00114 : ::coil::LogStream(streambuf,
00115 SILENT_LEVEL, PARANOID_LEVEL, SILENT_LEVEL)
00116 {
00117 }
00118 virtual ~LogOut(){}
00119
00120 virtual std::string& prefix(std::string& prefix, int level)
00121 {
00122 const char* level_str[] =
00123 {
00124 "SILENT ",
00125 "INFO ",
00126 "ERROR ",
00127 "TRACE ",
00128 "PARANOID "
00129 };
00130 prefix = getFmtDate() + level_str[level];
00131 return prefix;
00132 }
00133
00134 void setDateFormat(const char* format)
00135 {
00136 m_dateFormat = std::string(format);
00137 }
00138 void header(int level)
00139 {
00140 const char* level_str[] = {
00141 " SILENT :",
00142 " INFO :",
00143 " ERROR :",
00144 " TRACE :",
00145 " PARANOID:"
00146 };
00147 *this << getDate() + level_str[level] + m_name + ": ";
00148 }
00149 std::string getDate(void)
00150 {
00151 const int maxsize = 256;
00152 char buf[maxsize];
00153
00154 time_t timer;
00155 struct tm* date;
00156
00157 timer = time(NULL);
00158 date = localtime(&timer);
00159 strftime(buf, sizeof(buf), m_dateFormat.c_str(), date);
00160
00161 return std::string(buf);
00162 }
00163 void setName(const char* name)
00164 {
00165 m_name = name;
00166 }
00167 protected:
00168 std::string getFmtDate()
00169 {
00170 const int maxsize = 256;
00171 char buf[maxsize];
00172
00173 time_t timer;
00174 struct tm* date;
00175
00176 timer = time(NULL);
00177 date = localtime(&timer);
00178 strftime(buf, maxsize, "%b %d %H:%M:%S ", date);
00179
00180 return std::string(buf);
00181 }
00182 std::string m_name;
00183 std::string m_dateFormat;
00184 };
00185
00186 class LogOut2
00187 : public coil::LogStream
00188 {
00189
00190
00191 public:
00192 LogOut2(::coil::LogStream::streambuf_type* streambuf)
00193 : ::coil::LogStream(streambuf,
00194 SILENT_LEVEL, PARANOID_LEVEL, SILENT_LEVEL)
00195 {
00196 }
00197 virtual ~LogOut2(){}
00198
00199
00200 protected:
00201 };
00202
00203
00204
00205 #define RTC_LOG(LV, fmt) \
00206 if (m_out.isValid(LV)) \
00207 { \
00208 m_out.lock(); \
00209 m_out.level(LV) << ::coil::sprintf fmt << std::endl; \
00210 m_out.unlock(); \
00211 }
00212
00213 #define RTC_TRACE(fmt) RTC_LOG(TRACE_LEVEL, fmt)
00214
00215
00216 class LogOutCreator
00217 : public coil::Task
00218 {
00219 public:
00220 LogOutCreator(const char* name, coil::LogStreamBuffer *streambuf)
00221 : m_name(name),
00222 m_out(streambuf)
00223
00224 {
00225 m_out.setName(m_name.c_str());
00226 m_out.setDateFormat("%b %d %H:%M:%S");
00227 m_out.setLevel(PARANOID_LEVEL);
00228 m_out.enableLock();
00229 }
00230 ~LogOutCreator()
00231 {
00232 m_out.disableLock();
00233 }
00234
00235 virtual int svc()
00236 {
00237 coil::TimeMeasure tm;
00238 for (int i(0); i < 200; ++i)
00239 {
00240 double r(rand() / (double)RAND_MAX * 100.0);
00241 tm.tick();
00242 std::string str = coil::sprintf("svc() %03d %6.2f", i, r);
00243 RTC_TRACE((str.c_str()));
00244 tm.tack();
00245 coil::usleep((int)r);
00246 }
00247
00248 #if 0
00249 double max, min, mean, stddev;
00250 tm.getStatistics(max, min, mean, stddev);
00251 std::cout << m_name << std::endl;
00252 printf("max : %04.2f [us]\n", max * 1000000);
00253 printf("min : %04.2f [us]\n", min * 1000000);
00254 printf("mean : %04.2f [us]\n", mean * 1000000);
00255 printf("stddev: %04.2f [us]\n", stddev * 1000000);
00256 #endif
00257 return 0;
00258 }
00259
00260 private:
00261 std::string m_name;
00262 LogOut m_out;
00263 int dummy0(int ic)
00264 {
00265 RTC_TRACE(("IN dummy0"));
00266 RTC_TRACE((" ic=%d",ic));
00267 RTC_TRACE(("OUT dummy0"));
00268 return ic;
00269 }
00270
00271 };
00272
00273
00278 class LoggerTests
00279 : public CppUnit::TestFixture
00280 {
00281 CPPUNIT_TEST_SUITE(LoggerTests);
00282
00283 CPPUNIT_TEST(test_log_streambuf);
00284 CPPUNIT_TEST(test_log_streambuf2);
00285 CPPUNIT_TEST(test_log_stream);
00286 CPPUNIT_TEST(test_log_stream2);
00287 CPPUNIT_TEST(test_log_stream_properties);
00288 CPPUNIT_TEST(test_log_stream3);
00289
00290 CPPUNIT_TEST_SUITE_END();
00291
00292 private:
00293
00294 public:
00295
00299 LoggerTests()
00300 {
00301 }
00302
00306 ~LoggerTests()
00307 {
00308 }
00309
00313 virtual void setUp()
00314 {
00315 }
00316
00320 virtual void tearDown()
00321 {
00322
00323
00324 }
00325
00326
00327 void test_log_streambuf()
00328 {
00329 coil::LogStreamBuffer logger;
00330
00331 std::stringstream s0;
00332 std::stringstream s1;
00333 std::stringstream s2;
00334 std::filebuf f;
00335 f.open("log.log", std::ios::out);
00336
00337 logger.addStream(s0.rdbuf());
00338 logger.addStream(s1.rdbuf());
00339 logger.addStream(s2.rdbuf());
00340 logger.addStream(&f);
00341
00342 LogCreator l0("log0", &logger);
00343 LogCreator l1("log1", &logger);
00344 LogCreator l2("log2", &logger);
00345 LogCreator l3("log3", &logger);
00346
00347 l0.activate();
00348 l1.activate();
00349 l2.activate();
00350 l3.activate();
00351
00352 l0.wait();
00353 l1.wait();
00354 l2.wait();
00355 l3.wait();
00356
00357 std::ofstream f0("log0.log");
00358 std::ofstream f1("log1.log");
00359 std::ofstream f2("log2.log");
00360 f0 << s0.str() << std::endl;
00361 f1 << s1.str() << std::endl;
00362 f2 << s2.str() << std::endl;
00363 f0.close();
00364 f1.close();
00365 f2.close();
00366 CPPUNIT_ASSERT(s0.str() == s1.str());
00367 CPPUNIT_ASSERT(s1.str() == s2.str());
00368
00369
00370 std::string s;
00371 getline(s0, s);
00372 size_t len(s.size());
00373
00374 while (getline(s0, s))
00375 {
00376 CPPUNIT_ASSERT(len == s.size());
00377 }
00378 }
00379
00380 void test_log_streambuf2()
00381 {
00382 coil::LogStreamBuffer logger;
00383 std::stringstream s0;
00384
00385 logger.addStream(s0.rdbuf());
00386
00387 std::basic_ostream<char> out(&logger);
00388 std::string str("::");
00389 int ic(2);
00390 out <<"Logger"<<str<<"test_log_streambuf"<<ic<<std::endl;
00391 std::ostringstream os,osm;
00392 os <<"Logger"<<str<<"test_log_streambuf"<<ic<<std::endl;
00393 osm <<"s0.str():"<<s0.str()<<" os.str():"<<"Logger"<<str<<"test_log_streambuf"<<ic<<std::endl;
00394 CPPUNIT_ASSERT_MESSAGE(osm.str(),s0.str() == os.str());
00395
00396 }
00397
00398 void test_log_stream()
00399 {
00400 coil::LogStreamBuffer logbuf;
00401 std::stringstream s0;
00402 logbuf.addStream(s0.rdbuf());
00403
00404
00405 LogOut log(&logbuf);
00406 log.setLevel(PARANOID_LEVEL);
00407
00408 log.level(SILENT_LEVEL) << coil::sprintf("This is silent message.") << std::endl;
00409 log.level(INFO_LEVEL) << coil::sprintf("This is info message.") << std::endl;
00410 log.level(ERROR_LEVEL) << coil::sprintf("This is error message.") << std::endl;
00411 log.level(PARANOID_LEVEL) << coil::sprintf("This is paranoid message.") << std::endl;
00412
00413
00414 log.setLevel(INFO_LEVEL);
00415 log.level(SILENT_LEVEL) << coil::sprintf("This is silent message.") << std::endl;
00416 log.level(INFO_LEVEL) << coil::sprintf("This is info message.") << std::endl;
00417 log.level(ERROR_LEVEL) << coil::sprintf("This is error message.") << std::endl;
00418 log.level(PARANOID_LEVEL) << coil::sprintf("This is paranoid message.") << std::endl;
00419
00420
00421 log.setLevel(SILENT_LEVEL);
00422 log.level(SILENT_LEVEL) << coil::sprintf("This is silent message.") << std::endl;
00423 log.level(INFO_LEVEL) << coil::sprintf("This is info message.") << std::endl;
00424 log.level(ERROR_LEVEL) << coil::sprintf("This is error message.") << std::endl;
00425 log.level(PARANOID_LEVEL) << coil::sprintf("This is paranoid message.") << std::endl;
00426
00427 std::ofstream f0("test_log_stream.log");
00428 f0 << s0.str() << std::endl;
00429 f0.close();
00430
00431
00432 }
00433
00434 void test_log_stream2()
00435 {
00436 coil::LogStreamBuffer logger;
00437
00438 std::stringstream s0;
00439 std::stringstream s1;
00440 std::stringstream s2;
00441 std::filebuf f;
00442 f.open("log.log", std::ios::out);
00443
00444 logger.addStream(s0.rdbuf());
00445 logger.addStream(s1.rdbuf());
00446 logger.addStream(s2.rdbuf());
00447 logger.addStream(&f);
00448
00449 LogOutCreator l0("test_log_stream_log0", &logger);
00450 LogOutCreator l1("test_log_stream_log1", &logger);
00451 LogOutCreator l2("test_log_stream_log2", &logger);
00452 LogOutCreator l3("test_log_stream_log3", &logger);
00453
00454 l0.activate();
00455 l1.activate();
00456 l2.activate();
00457 l3.activate();
00458
00459 l0.wait();
00460 l1.wait();
00461 l2.wait();
00462 l3.wait();
00463
00464 std::ofstream f0("log4.log");
00465 std::ofstream f1("log5.log");
00466 std::ofstream f2("log6.log");
00467 f0 << s0.str() << std::endl;
00468 f1 << s1.str() << std::endl;
00469 f2 << s2.str() << std::endl;
00470 f0.close();
00471 f1.close();
00472 f2.close();
00473 CPPUNIT_ASSERT(s0.str() == s1.str());
00474 CPPUNIT_ASSERT(s1.str() == s2.str());
00475
00476
00477 std::string s;
00478 getline(s0, s);
00479 size_t len(s.size());
00480
00481 while (getline(s0, s))
00482 {
00483 CPPUNIT_ASSERT(len == s.size());
00484 }
00485 }
00486
00487 void test_log_stream3()
00488 {
00489
00490
00491
00492 coil::LogStreamBuffer logbuf;
00493
00494 LogOut log(&logbuf);
00495 std::filebuf* of = new std::filebuf();
00496 of->open("test_log_stream3-1.log", std::ios::out | std::ios::app);
00497 logbuf.addStream(of);
00498
00499 std::filebuf f;
00500 f.open("test_log_stream3-2.log", std::ios::out | std::ios::app);
00501 logbuf.addStream(&f);
00502
00503
00504 log.setLevel(INFO_LEVEL);
00505 log.level(SILENT_LEVEL) << coil::sprintf("This is silent message.") << std::endl;
00506 log.level(INFO_LEVEL) << coil::sprintf("This is info message.") << std::endl;
00507 log.level(ERROR_LEVEL) << coil::sprintf("This is error message.") << std::endl;
00508 log.level(PARANOID_LEVEL) << coil::sprintf("This is paranoid message.") << std::endl;
00509
00510 CPPUNIT_ASSERT_EQUAL(true, logbuf.removeStream(&f));
00511 std::vector< ::coil::LogStream::streambuf_type* > vt;
00512 vt = logbuf.getBuffers();
00513 CPPUNIT_ASSERT_EQUAL(1, (int)vt.size());
00514 for (int i(0), len(vt.size()); i < len; ++i)
00515 {
00516 try
00517 {
00518 CPPUNIT_ASSERT(of==vt[i]);
00519 delete vt[i];
00520 }
00521 catch(...)
00522 {
00523 CPPUNIT_FAIL( "Exception thrown." );
00524 }
00525
00526 }
00527
00528 }
00529 void test_log_stream_properties()
00530 {
00531 std::map<std::string, std::string> defaults;
00532 defaults["rtc.component.conf.path"] = "C:\\Program\\ Files\\OpenRTM-aist";
00533 defaults["rtc.manager.arch"] = "i386";
00534 defaults["rtc.manager.nameserver"] = "zonu.a02.aist.go.jp";
00535 defaults["rtc.manager.opening_message"] = "Hello World";
00536
00537 coil::Properties prop(defaults);
00538
00539 coil::LogStreamBuffer logbuf;
00540 std::stringstream s0;
00541 logbuf.addStream(s0.rdbuf());
00542
00543
00544 LogOut2 log(&logbuf);
00545 log.setLevel(PARANOID_LEVEL);
00546
00547 log.level(PARANOID_LEVEL) << prop;
00548
00549 std::ostringstream os,osm;
00550 os << prop;
00551 osm<<"---s0.str---"<<std::endl;
00552 osm<<s0.str()<<std::endl;
00553 osm<<"---os.str---"<<std::endl;
00554 osm<<os.str()<<std::endl;
00555 CPPUNIT_ASSERT_MESSAGE(osm.str(),s0.str() == os.str());
00556
00557 }
00558
00559 };
00560 };
00561
00562
00563
00564
00565 CPPUNIT_TEST_SUITE_REGISTRATION(Logger::LoggerTests);
00566
00567 #ifdef LOCAL_MAIN
00568 int main(int argc, char* argv[])
00569 {
00570 CppUnit::TextUi::TestRunner runner;
00571 runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
00572 CppUnit::Outputter* outputter =
00573 new CppUnit::TextOutputter(&runner.result(), std::cout);
00574 runner.setOutputter(outputter);
00575 bool retcode = runner.run();
00576 return !retcode;
00577 }
00578 #endif // MAIN
00579 #endif // Logger_cpp