00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "Log.h"
00034 #include "FileUtil.h"
00035 #include "StrUtil.h"
00036 #include "SockUtil.h"
00037 #include "Util.h"
00038 #include "TimeUtil.h"
00039 #include "pip_includer.h"
00040 #include "params.h"
00041
00042 #include <fstream>
00043 #include <assert.h>
00044
00045 #define DEFAULT_MACE_BIN_LOG_FILE "binarylog"
00046
00047 using namespace std;
00048
00049
00050 bool Log::enabled = true;
00051 bool Log::autoAll = false;
00052 bool Log::errorSelected = true;
00053 bool Log::warningSelected = true;
00054 const bool Log::FLUSH = true;
00055 const log_level_t Log::DEFAULT_LEVEL = 0;
00056 const log_level_t Log::MAX_LEVEL = UINT_MAX;
00057 log_level_t Log::logLevel = DEFAULT_LEVEL;
00058 Log::SelectorMap Log::selectors;
00059 Log::IdSelectorList Log::selectorLists(1);
00060 Log::LogFileMap Log::logFiles;
00061 Log::SelectorList Log::autoSelectors;
00062 Log::SelectorIdMap Log::ids;
00063 Log::IdSelectorMap Log::reverseIds;
00064 LogSelector* Log::autoAllDefault = 0;
00065 pthread_mutex_t Log::llock = PTHREAD_MUTEX_INITIALIZER;
00066 uint32_t Log::idCount = 1;
00067 const log_id_t Log::NULL_ID = 0;
00068 const size_t Log::MAX_MESSAGE_SIZE = 4096;
00069 Log::NullOutputType Log::nullOutputVar;
00070 Log::LogFlushManipulator Log::end;
00071 Log::LogFlushManipulator Log::endl;
00072 std::ifstream Log::replayStream;
00073
00074 pthread_key_t Log::ThreadSpecific::pkey;
00075 pthread_once_t Log::ThreadSpecific::keyOnce = PTHREAD_ONCE_INIT;
00076 unsigned int Log::ThreadSpecific::count = 0;
00077
00078 static FILE* binout = NULL;
00079
00080 Log::ThreadSpecific::ThreadSpecific() {
00081 count++;
00082 vtid = count;
00083 }
00084
00085 Log::ThreadSpecific::~ThreadSpecific() {
00086 }
00087
00088 Log::ThreadSpecific* Log::ThreadSpecific::init() {
00089 pthread_once(&keyOnce, Log::ThreadSpecific::initKey);
00090 ThreadSpecific* t = (ThreadSpecific*)pthread_getspecific(pkey);
00091 if (t == 0) {
00092 t = new ThreadSpecific();
00093 assert(pthread_setspecific(pkey, t) == 0);
00094 }
00095
00096 return t;
00097 }
00098
00099 void Log::ThreadSpecific::initKey() {
00100 assert(pthread_key_create(&pkey, NULL) == 0);
00101 }
00102
00103 unsigned int Log::ThreadSpecific::getVtid() {
00104 ThreadSpecific* t = (ThreadSpecific*)init();
00105 return t->vtid;
00106 }
00107
00108 Log::StreamMap& Log::ThreadSpecific::getStreams() {
00109 ThreadSpecific* t = (ThreadSpecific*)init();
00110 return t->streams;
00111 }
00112
00113 Log::TraceStreamMap& Log::ThreadSpecific::getTraceStreams() {
00114 ThreadSpecific* t = (ThreadSpecific*)init();
00115 return t->traceStreams;
00116 }
00117
00118 log_id_t Log::getId(const std::string& selector) {
00119 log_id_t r = NULL_ID;
00120 lock();
00121 SelectorIdMap::iterator i = ids.find(selector);
00122 if (i == ids.end()) {
00123 if (isSelected(selector)) {
00124 SelectorList* l = selectors[selector];
00125 r = idCount;
00126 idCount++;
00127 selectorLists.push_back(l);
00128
00129
00130
00131
00132 for (SelectorList::const_iterator i = l->begin(); i != l->end(); i++) {
00133 const LogSelector* sel = *i;
00134 if (sel->getLogSelectorOutput() == LOG_BINARY){
00135
00136
00137 writeBinaryLog(r, sel, "M", selector);
00138 break;
00139 }
00140 }
00141 reverseIds[r] = selector;
00142 }
00143 ids[selector] = r;
00144 }
00145 else {
00146 r = i->second;
00147 }
00148
00149 unlock();
00150 return r;
00151 }
00152
00153 const std::string& Log::getSelector(log_id_t id) {
00154 static const std::string empty;
00155 if (id == NULL_ID) {
00156 return empty;
00157 }
00158 return reverseIds.get(id);
00159 }
00160
00161 Log::MaceOutputStream& Log::log(const std::string& selector, log_level_t level) {
00162 return log(getId(selector), level);
00163 }
00164
00165 void Log::log(log_id_t id, log_id_t level, const std::string& m) {
00166 if (!enabled || id == NULL_ID || level > logLevel) {
00167 return;
00168 }
00169
00170 log(id, level, m.c_str());
00171 }
00172
00173 void Log::log(log_id_t id, log_id_t level, const char* m) {
00174 if (!enabled || id == NULL_ID || level > logLevel) {
00175 return;
00176 }
00177
00178
00179 SelectorList* l = selectorLists[id];
00180 for (SelectorList::const_iterator i = l->begin(); i != l->end(); i++) {
00181 const LogSelector* sel = *i;
00182 switch(sel->getLogSelectorOutput()) {
00183 case LOG_BINARY: {
00184 writeBinaryLog(id, sel, "S", m);
00185 }
00186 break;
00187 case LOG_FPRINTF:
00188 case LOG_PIP:
00189 {
00190 writeTextLog(sel, m);
00191 }
00192 break;
00193 default:
00194 ABORT("Unrecognized log style");
00195 }
00196 }
00197 }
00198
00199 void Log::logf(log_id_t id, log_level_t level, const char* f ...) {
00200 if (!enabled || id == NULL_ID || level > logLevel) {
00201 return;
00202 }
00203
00204 va_list ap;
00205 va_start(ap, f);
00206 char tmp[MAX_MESSAGE_SIZE];
00207 vsnprintf(tmp, MAX_MESSAGE_SIZE - 1, f, ap);
00208 va_end(ap);
00209 log(id, level, tmp);
00210 }
00211
00212 void Log::logf(log_id_t id, const char* f ...) {
00213 if (!enabled || id == NULL_ID) {
00214 return;
00215 }
00216
00217 va_list ap;
00218 va_start(ap, f);
00219 char tmp[MAX_MESSAGE_SIZE];
00220 vsnprintf(tmp, MAX_MESSAGE_SIZE - 1, f, ap);
00221 va_end(ap);
00222 log(id, tmp);
00223 }
00224
00225 Log::MaceOutputStream& Log::log(log_id_t id, log_level_t level) {
00226 static MaceOutputStream* nullOutStr = new MaceOutputStream();
00227 if (id == NULL_ID || level > logLevel) {
00228 return *nullOutStr;
00229 }
00230 StreamMap& m = ThreadSpecific::getStreams();
00231
00232
00233 StreamMap::iterator i = m.find(id);
00234 MaceOutputStream* r = 0;
00235 if (i == m.end()) {
00236 r = new MaceOutputStream(id);
00237 m[id] = r;
00238 }
00239 else {
00240 r = i->second;
00241 }
00242
00243
00244
00245
00246
00247
00248
00249 return *r;
00250 }
00251
00252 void Log::binaryLog(log_id_t id, const std::string& log_type,
00253 const std::string& serializedObj, log_level_t level) {
00254
00255 if (id == NULL_ID || level > logLevel) {
00256 return;
00257 }
00258
00259
00260
00261 SelectorList* l = selectorLists[id];
00262 for (SelectorList::const_iterator i = l->begin(); i != l->end(); i++) {
00263 const LogSelector* sel = *i;
00264 if (sel->getLogSelectorOutput() == LOG_BINARY) {
00265 writeBinaryLog(id, sel, log_type, serializedObj);
00266 }
00267 }
00268 }
00269
00270 void Log::binaryLog(log_id_t id, const mace::BinaryLogObject& object, log_level_t level) {
00271
00272
00273 if (id == NULL_ID || level > logLevel) {
00274 return;
00275 }
00276
00277 std::string serializedObj("");
00278 std::string text("");
00279
00280
00281 SelectorList* l = selectorLists[id];
00282 for (SelectorList::const_iterator i = l->begin(); i != l->end(); i++) {
00283 const LogSelector* sel = *i;
00284 switch(sel->getLogSelectorOutput()) {
00285 case LOG_BINARY: {
00286 if (serializedObj == "") {
00287 mace::serialize(serializedObj, &object);
00288 }
00289 writeBinaryLog(id, sel, object.getLogType(), serializedObj);
00290 }
00291 break;
00292 case LOG_FPRINTF:
00293 case LOG_PIP: {
00294 if (text == "") {
00295 text = object.getLogDescription() + ": " + object.toString();
00296 }
00297 writeTextLog(sel, text.c_str());
00298 }
00299 break;
00300 default:
00301 ABORT("INVALID LogSelectorOutput");
00302 }
00303 }
00304 }
00305
00306
00311 void Log::writeBinaryLog(log_id_t id, const LogSelector* sel, const std::string& log_type, const std::string& serializedObj) {
00312 ASSERT(!log_type.empty());
00313 std::string str;
00314
00315
00316 mace::serialize(str, &id);
00317 str += sel->getSerializedSelectorHeader();
00318 mace::serialize(str, &log_type);
00319
00320
00321 mace::serialize(str, &serializedObj);
00322 fwrite(str.data(), 1, str.size(), sel->getFile());
00323
00324
00325 if (FLUSH){
00326 fflush(sel->getFile());
00327 }
00328 }
00329
00334 void Log::writeTextLog(const LogSelector* sel, const char* text) {
00335 static const bool SCOPED_LOG_TIMES = params::get(params::MACE_LOG_SCOPED_TIMES,
00336 false);
00337
00338 if(sel->getLogSelectorOutput() == LOG_FPRINTF) {
00339 fprintf(sel->getFile(), "%s%s\n", sel->getSelectorHeader().c_str(), text);
00340 } else {
00341 ASSERT(sel->getLogSelectorOutput() == LOG_PIP);
00342 #ifdef PIP_MESSAGING
00343 ANNOTATE_NOTICE(sel->getSelectorHeader().c_str(), 4 + level, "%s", text);
00344 #else
00345 fprintf(sel->getFile(), "%s%s\n", sel->getSelectorHeader().c_str(), text);
00346 #endif
00347 }
00348 if (FLUSH && !SCOPED_LOG_TIMES) {
00349 fflush(sel->getFile());
00350 }
00351 }
00352
00353 void Log::flush(MaceOutputStream& str) {
00354
00355 if (str.stream != NULL) {
00356 log(str.id, str.stream->str().c_str());
00357 str.stream->str("");
00358 }
00359 }
00360
00361 void Log::autoAddAll(FILE* f,
00362 LogSelectorTimestamp lt,
00363 LogSelectorName ln,
00364 LogSelectorThreadId ltid,
00365 LogSelectorOutput lso) {
00366
00367 if (autoAllDefault != 0) {
00368 delete autoAllDefault;
00369 }
00370
00371 autoAll = true;
00372 autoAllDefault = new LogSelector("", f, lt, ln, ltid, lso);
00373 }
00374
00375 void Log::autoAdd(const string& s,
00376 FILE* f,
00377 LogSelectorTimestamp lt,
00378 LogSelectorName ln,
00379 LogSelectorThreadId ltid,
00380 LogSelectorOutput lso) {
00381
00382 LogSelector* sel = new LogSelector(s, f, lt, ln, ltid, lso);
00383 autoSelectors.push_back(sel);
00384 }
00385
00386 void Log::add(const string& s,
00387 FILE* f,
00388 LogSelectorTimestamp lt,
00389 LogSelectorName ln,
00390 LogSelectorThreadId ltid,
00391 LogSelectorOutput lso) {
00392 lock();
00393
00394
00395 isSelected(s);
00396
00397 if (lso == LOG_BINARY) {
00398 if (binout == NULL) {
00399 binout = openLogFile(params::get<std::string>(params::MACE_BIN_LOG_FILE, DEFAULT_MACE_BIN_LOG_FILE), "wb");
00400 }
00401 f = binout;
00402 }
00403
00404 addl(s, f, lt, ln, ltid, lso);
00405 unlock();
00406 }
00407
00408 void Log::addl(const string& s,
00409 FILE* f,
00410 LogSelectorTimestamp lt,
00411 LogSelectorName ln,
00412 LogSelectorThreadId ltid,
00413 LogSelectorOutput lso) {
00414
00415
00416
00417 SelectorList* l;
00418 SelectorMap::iterator i = selectors.find(s);
00419 if (i != selectors.end()) {
00420 l = i->second;
00421 }
00422 else {
00423 l = new SelectorList();
00424 selectors[s] = l;
00425 }
00426
00427
00428 remove(l, f);
00429
00430 LogSelector* sel = new LogSelector(s, f, lt, ln, ltid, lso);
00431 l->push_back(sel);
00432
00433 }
00434
00435 void Log::remove(const string& s, FILE* f) {
00436 if (selectors.containsKey(s)) {
00437 SelectorList* l = selectors[s];
00438 remove(l, f);
00439 }
00440 }
00441
00442 void Log::remove(SelectorList* l, FILE* f) {
00443 SelectorList::iterator i = l->begin();
00444 while (i != l->end()) {
00445 if ((*i)->getFile() == f) {
00446 delete *i;
00447 *i = 0;
00448 i = l->erase(i);
00449 }
00450 else {
00451 i++;
00452 }
00453 }
00454 }
00455
00456 void Log::removeAll(const string& s) {
00457 if (selectors.find(s) != selectors.end()) {
00458 SelectorList* l = selectors[s];
00459 for (SelectorList::iterator i = l->begin(); i != l->end(); i++) {
00460 delete *i;
00461 }
00462 delete l;
00463 selectors.erase(s);
00464 }
00465 }
00466
00467 void Log::logToFile(const string& path, const string& sel, const char* mode,
00468 LogSelectorTimestamp sts, LogSelectorName sn,
00469 LogSelectorThreadId stid) {
00470 FILE* f = openLogFile(path, mode);
00471 add(sel, f, sts, sn, stid);
00472 }
00473
00474 FILE* Log::openLogFile(const string& path, const char* mode) {
00475 if (logFiles.find(path) != logFiles.end()) {
00476 return logFiles[path];
00477 }
00478
00479 FILE* f = fopen(path.c_str(), mode);
00480 if (f == 0) {
00481 fprintf(stderr, "could not open log file %s, aborting\n", path.c_str());
00482 ::perror("open");
00483 exit(-1);
00484 }
00485
00486 logFiles[path] = f;
00487 return f;
00488 }
00489
00490 void Log::closeLogFiles() {
00491 for (LogFileMap::iterator i = logFiles.begin(); i != logFiles.end(); i++) {
00492 FILE* f = i->second;
00493 fclose(f);
00494 }
00495 }
00496
00497 void Log::enableLogging() {
00498 enabled = true;
00499 }
00500
00501 void Log::disableLogging() {
00502 enabled = false;
00503 }
00504
00505 void Log::log(const std::string& selector, log_level_t level, const string& message) {
00506 if (!enabled || level > logLevel) {
00507 return;
00508 }
00509
00510 log(selector, message.c_str());
00511 }
00512
00513 bool Log::isSelected(const string& s) {
00514 bool r = true;
00515 if (!selectors.containsKey(s)) {
00516 r = false;
00517 if (errorSelected && s.find("ERROR") != string::npos) {
00518 addl(s,
00519 stderr,
00520 LOG_TIMESTAMP_DISABLED,
00521 LOG_NAME_ENABLED,
00522 LOG_THREADID_DISABLED,
00523 LOG_FPRINTF);
00524 r = true;
00525 }
00526 if (warningSelected && s.find("WARNING") != string::npos) {
00527 addl(s,
00528 stdout,
00529 LOG_TIMESTAMP_DISABLED,
00530 LOG_NAME_ENABLED,
00531 LOG_THREADID_DISABLED,
00532 LOG_FPRINTF);
00533 r = true;
00534 }
00535 if (autoAll) {
00536 assert(autoAllDefault != 0);
00537 FILE* out = autoAllDefault->getFile();
00538 if (autoAllDefault->getLogSelectorOutput() == LOG_BINARY) {
00539 if (binout == NULL) {
00540 binout = openLogFile(params::get<std::string>(params::MACE_BIN_LOG_FILE, DEFAULT_MACE_BIN_LOG_FILE), "wb");
00541 }
00542 out = binout;
00543 }
00544 addl(s,
00545 out,
00546 autoAllDefault->getLogTimestamp(),
00547 autoAllDefault->getLogName(),
00548 autoAllDefault->getLogThreadId(),
00549 autoAllDefault->getLogSelectorOutput());
00550 return true;
00551 }
00552 else if (!autoSelectors.empty()) {
00553 for (SelectorList::iterator i = autoSelectors.begin();
00554 i != autoSelectors.end(); i++) {
00555 LogSelector* sel = *i;
00556 if (StrUtil::matches(sel->getName(), s)) {
00557 FILE* out = sel->getFile();
00558 if (sel->getLogSelectorOutput() == LOG_BINARY) {
00559 if (binout == NULL) {
00560 binout = openLogFile(params::get<std::string>(params::MACE_BIN_LOG_FILE, DEFAULT_MACE_BIN_LOG_FILE), "wb");
00561 }
00562 out = binout;
00563 }
00564 addl(s,
00565 out,
00566 sel->getLogTimestamp(),
00567 sel->getLogName(),
00568 sel->getLogThreadId(),
00569 sel->getLogSelectorOutput());
00570 r = true;
00571 }
00572 }
00573 }
00574 }
00575 return r;
00576 }
00577
00578 void Log::log(const string& s, log_level_t level, const char* m) {
00579 if (!enabled || level > logLevel) {
00580 return;
00581 }
00582
00583 log(getId(s), level, m);
00584 }
00585
00586 void Log::logf(const string& s, log_level_t level, const char* f ...) {
00587 if (!enabled || level > logLevel) {
00588 return;
00589 }
00590
00591 va_list ap;
00592 va_start(ap, f);
00593 char tmp[MAX_MESSAGE_SIZE];
00594 vsnprintf(tmp, MAX_MESSAGE_SIZE - 1, f, ap);
00595 va_end(ap);
00596 log(s, level, tmp);
00597 }
00598
00599 void Log::logf(const string& s, const char* f ...) {
00600 if (!enabled) {
00601 return;
00602 }
00603
00604 va_list ap;
00605 va_start(ap, f);
00606 char tmp[MAX_MESSAGE_SIZE];
00607 vsnprintf(tmp, MAX_MESSAGE_SIZE - 1, f, ap);
00608 va_end(ap);
00609 log(s, tmp);
00610 }
00611
00612 string Log::toHex(const string& h) {
00613 string r = "";
00614 for (size_t i = 0; i < h.size(); i++) {
00615 char c[3];
00616 sprintf(c, "%02hhx", (unsigned char)h[i]);
00617 r += c;
00618 }
00619 return r;
00620 }
00621
00622 void Log::configure() {
00623 LogSelectorTimestamp lts = LOG_TIMESTAMP_EPOCH;
00624 if (params::get(params::MACE_LOG_TIMESTAMP_HUMAN, false)) {
00625 lts = LOG_TIMESTAMP_HUMAN;
00626 }
00627
00628 if (params::containsKey(params::MACE_LOG_LEVEL)) {
00629 int l = params::get<int>(params::MACE_LOG_LEVEL);
00630 setLevel(l == -1 ? MAX_LEVEL : l);
00631 }
00632
00633 if (params::get(params::MACE_LOG_DISABLE_WARNING, false)) {
00634 disableDefaultWarning();
00635 }
00636
00637 string filemode = "w";
00638 if (params::get(params::MACE_LOG_APPEND, false)) {
00639 filemode = "a";
00640 }
00641
00642 string prefix = params::get(params::MACE_LOG_PREFIX, string());
00643 string logpath = params::get(params::MACE_LOG_PATH, string());
00644 if (!logpath.empty()) {
00645
00646 FileUtil::mkdir(logpath, S_IRWXU, true);
00647 if (logpath[logpath.size() - 1] != '/') {
00648 logpath.append("/");
00649 }
00650 }
00651 FILE* fp = stdout;
00652 if (params::containsKey(params::MACE_LOG_FILE)) {
00653 StringList s = StrUtil::split("\n", params::get<string>(params::MACE_LOG_FILE));
00654 for (StringList::const_iterator i = s.begin(); i != s.end(); i++) {
00655 StringList l = StrUtil::split(" ", *i);
00656 if (l.size() == 1) {
00657
00658 fp = openLogFile(logpath + prefix + l[0], filemode.c_str());
00659 }
00660 else {
00661 string path = l.front();
00662 l.pop_front();
00663 for (StringList::const_iterator li = l.begin(); li != l.end(); li++) {
00664
00665 logToFile(logpath + prefix + path, *li, filemode.c_str(), lts);
00666 }
00667 }
00668 }
00669
00670 }
00671
00672 if (params::get(params::MACE_LOG_AUTO_ALL, false)) {
00673 autoAddAll(fp, lts);
00674 return;
00675 }
00676
00677 if (params::containsKey(params::MACE_LOG_AUTO_SELECTORS)) {
00678 string tmp = params::get<string>(params::MACE_LOG_AUTO_SELECTORS);
00679
00680 StringList s = StrUtil::split(" ", tmp);
00681 for (StringList::const_iterator i = s.begin(); i != s.end(); i++) {
00682 autoAdd(*i, fp, lts);
00683 }
00684 }
00685
00686 if (params::containsKey(params::MACE_LOG_AUTO_BINARY)) {
00687 string tmp = params::get<string>(params::MACE_LOG_AUTO_BINARY);
00688
00689 StringList s = StrUtil::split(" ", tmp);
00690 for (StringList::const_iterator i = s.begin(); i != s.end(); i++) {
00691 autoAdd(*i, stdout, LOG_TIMESTAMP_HUMAN, LOG_NAME_ENABLED, LOG_THREADID_ENABLED, LOG_BINARY);
00692 }
00693 }
00694 }
00695
00696 void Log::perror(const std::string& s) {
00697 int err = SockUtil::getErrno();
00698 Log::err() << s << ": errno " << errno << ": " << Util::getErrorString(errno);
00699 std::cerr << s << ": errno " << errno << ": " << Util::getErrorString(errno);
00700 if (errno != err) {
00701 Log::err() << ", socket " << err << ": " << Util::getErrorString(err);
00702 std::cerr << ", socket " << err << ": " << Util::getErrorString(err);
00703 }
00704 Log::err() << Log::endl;
00705 std::cerr << std::endl;
00706 }
00707
00708 void Log::sslerror(const std::string& s) {
00709 Log::err() << s << ": " << Util::getSslErrorString() << Log::endl;
00710 std::cerr << s << ": " << Util::getSslErrorString() << std::endl;
00711 }
00712
00713 void Log::lock() {
00714 assert(pthread_mutex_lock(&llock) == 0);
00715 }
00716
00717 void Log::unlock() {
00718 assert(pthread_mutex_unlock(&llock) == 0);
00719 }
00720
00721 log_id_t Log::getTraceId(const std::string& selector) {
00722 static const bool isTrace = params::containsKey(params::MACE_TRACE_FILE);
00723 if (isTrace) {
00724 return UINT_MAX;
00725 }
00726 else {
00727 return NULL_ID;
00728 }
00729 }
00730
00731 Log::MaceTraceStream& Log::trace(log_id_t id) {
00732 TraceStreamMap& m = ThreadSpecific::getTraceStreams();
00733
00734
00735 TraceStreamMap::iterator i = m.find(id);
00736 MaceTraceStream* r = 0;
00737 if (i == m.end()) {
00738 r = new MaceTraceStream(id);
00739 m[id] = r;
00740 }
00741 else {
00742 r = i->second;
00743 }
00744
00745 return *r;
00746 }
00747
00748 void Log::flush(Log::MaceTraceStream& s) {
00749 if (s.isNoop()) {
00750 return;
00751 }
00752 static FILE* out = openLogFile(params::get<std::string>(params::MACE_TRACE_FILE), "wb");
00753
00754 unsigned int vtid = ThreadSpecific::getVtid();
00755 vtid = htonl(vtid);
00756 fwrite(&vtid, sizeof(vtid), 1, out);
00757 fwrite(s.stream->str().data(), 1, s.stream->str().size(), out);
00758 fflush(out);
00759 s.stream->str("");
00760 }
00761
00762 void Log::traceNewThread(const mace::string& fname) {
00763 if (Util::REPLAY) {
00764 scheduleThread(UINT_MAX, fname);
00765 }
00766 else {
00767 if (!params::containsKey(params::MACE_TRACE_FILE)) {
00768 return;
00769 }
00770 static FILE* out = openLogFile(params::get<std::string>(params::MACE_TRACE_FILE), "wb");
00771
00772 unsigned int vtid = htonl(UINT_MAX);
00773 fwrite(&vtid, sizeof(vtid), 1, out);
00774 std::string s;
00775 mace::serialize(s, &fname);
00776 fwrite(s.data(), 1, s.size(), out);
00777 fflush(out);
00778 }
00779 }
00780
00781 std::istream& Log::replay(log_id_t id) {
00782 scheduleThread(ThreadSpecific::getVtid(), "");
00783 return replayStream;
00784 }
00785
00786 void Log::scheduleThread(unsigned int vtid, const mace::string& desc) {
00787 static pthread_cond_t sig = PTHREAD_COND_INITIALIZER;
00788 static uint curId = UINT_MAX;
00789 static mace::string curDesc = desc;
00790
00791 ASSERT(Util::REPLAY);
00792
00793 lock();
00794 if (!replayStream.is_open()) {
00795 replayStream.open(params::get<std::string>(params::MACE_TRACE_FILE).c_str());
00796 }
00797 ASSERT(replayStream);
00798
00799 if (vtid != UINT_MAX) {
00800 mace::deserialize(replayStream, &curId);
00801 if (curId == UINT_MAX) {
00802 mace::deserialize(replayStream, &curDesc);
00803 }
00804 pthread_cond_broadcast(&sig);
00805 }
00806
00807 while (vtid != curId || (vtid == UINT_MAX && desc != curDesc)) {
00808 pthread_cond_wait(&sig, &llock);
00809 }
00810 unlock();
00811 }