ROOT logo
// $Id: ZLog.cxx 2772 2012-06-12 22:42:02Z matevz $

// Copyright (C) 1999-2008, Matevz Tadel. All rights reserved.
// This file is part of GLED, released under GNU General Public License version 2.
// For the licensing terms see $GLEDSYS/LICENSE or http://www.gnu.org/.

#include "ZLog.h"
#include "ZLog.c7"

#include "Gled/GThread.h"

#include "TSystem.h"
#include "Varargs.h"

#include <time.h>

// ZLog

//______________________________________________________________________________
//
// Fast, preliminary implementation to plug a hole in XrdMonSucker.
// Needs more work ...
//
// Short term:
// - Various helper / access functions to make it easier to use.
//
// Medium term:
// - Log rotation,
// - Do output in the dedicated thread. (not 100% sure this is smart)
//
// Long term:
// - GUI (yes, right).

ClassImp(ZLog);

//==============================================================================

void ZLog::_init()
{
  mFileName = mName + ".log";
  mLevel = L_Message;
  mDebugLevel = 0;

  mLoggerThread = 0;
}

ZLog::ZLog(const Text_t* n, const Text_t* t) :
  ZGlass(n, t)
{
  _init();
}

ZLog::~ZLog()
{}

//==============================================================================

// void ZLog::operator()(Int_t level, const char* sth)
// {
//   clock_t clk = clock();
//   printf("Clocka %lu %lu\n", clk, clk / CLOCKS_PER_SEC);
//   printf("Jebojebo, got lvl=%d, txt='%s'\n", level, sth);
// }

//==============================================================================

void ZLog::StartLogging()
{
  static const Exc_t _eh("ZLog::StartLogging ");

  {
    GMutexHolder _lck(mLoggerCond);

    if (mLoggerThread != 0)
      throw _eh + "Logging already active.";

    mStream.open(mFileName, ios_base::out | ios_base::app);
    if (mStream.fail())
      throw _eh + "Opening of log '" + mFileName + "' failed.";

    mStream << "******************** Logging started at " << GTime::ApproximateTime().ToDateTimeLocal(false) << " ********************" << endl;

    mLoggerThread = new GThread("ZLog-LogLoop", (GThread_foo) tl_LogLoop, this);
    mLoggerThread->SetNice(20);
    mLoggerThread->Spawn();
  }

  {
    GLensReadHolder _rdlck(this);
    bLogActive = true;
    Stamp(FID());
  }
}

void ZLog::StopLogging()
{
  static const Exc_t _eh("ZLog::StopLogging ");

  {
    GMutexHolder _lck(mLoggerCond);

    if ( ! GThread::IsValidPtr(mLoggerThread))
      throw _eh + "Logging not active.";

    GThread *thr = mLoggerThread;
    GThread::InvalidatePtr(mLoggerThread);
    thr->Cancel();
    thr->Join();

    mStream << "******************** Logging stopped at " << GTime::ApproximateTime().ToDateTimeLocal(false) << " ********************" << endl;
    mStream.close();
    mLoggerThread = 0;
  }

  {
    GLensReadHolder _rdlck(this);
    bLogActive = false;
    Stamp(FID());
  }

}

void ZLog::RotateLog()
{
  static const Exc_t _eh("ZLog::RotateLog ");

  GMutexHolder _lck(mLoggerCond);

  if ( ! GThread::IsValidPtr(mLoggerThread))
    throw _eh + "Logging not active.";

  if (gSystem->AccessPathName(mFileName, kFileExists) == false)
  {
    TString newfile = mFileName + "." + GTime::ApproximateTime().ToDateLocal();
    if (gSystem->AccessPathName(newfile, kFileExists) == false)
    {
      Int_t cnt = 1;
      newfile += ".";
      TString tstr;
      do
      {
        tstr = newfile;
        tstr += cnt++;
      }
      while (gSystem->AccessPathName(tstr, kFileExists) == false);
      newfile = tstr;
    }
    gSystem->Rename(mFileName, newfile);
  }

  mLoggerThread->Kill(GThread::SigUSR1);
}

//------------------------------------------------------------------------------

void ZLog::tl_LogLoop(ZLog* log)
{
  log->LogLoop();
}

void ZLog::LogLoop()
{
  // Takes care of log rotation.
  //
  // Should we also have message queue for log entries?

  static const Exc_t _eh("ZLog::LogLoop ");

  GThread::UnblockSignal(GThread::SigUSR1);

  while (true)
  {
    GTime::SleepMiliSec(10*1000, true, false);

    if (gSystem->AccessPathName(mFileName, kFileExists) == true)
    {
      TString time(GTime::ApproximateTime().ToDateTimeLocal(false));
      GMutexHolder _lck(mLoggerCond);
      mStream << "******************** Logging rotated at " << time << " ********************" << endl;
      mStream.close();
      mStream.open(mFileName, ios_base::out | ios_base::app);
      if (mStream.fail())
      {
        ISerr(_eh + "Opening of log '" + mFileName + "' failed. Requesting logging termination.");
        mSaturn->ShootMIR(S_StopLogging());
      }
      mStream << "******************** Logging rotated at " << time << " ********************" << endl;
    }
  }
}

//==============================================================================

namespace
{
  static const char *lvl_names[] = { "FTL", "ERR", "WRN", "MSG", "INF", "DBG" };
}

#define LEVEL_CHECK(_lvl_) \
  if (mLevel < L_Debug) { \
    if (_lvl_ > mLevel) return; \
  } else { \
    if (_lvl_ > L_Debug + mDebugLevel) return; \
  }

#define LEVEL_NAME(_name_, _lvl_) \
  TString _name_; \
  if (_lvl_ <= L_Debug) { \
    _name_ = lvl_names[_lvl_]; \
  } else { \
    _name_ = lvl_names[L_Debug]; \
    _name_ += char('0' + _lvl_ - L_Debug); \
  }

void ZLog::Put(Int_t level, const TString& prefix, const TString& message)
{
  Put(GTime::ApproximateTime().ToDateTimeLocal(false), level, prefix, message);
}

void ZLog::Put(const GTime& time, Int_t level, const TString& prefix, const TString& message)
{
  Put(time.ToDateTimeLocal(false), level, prefix, message);
}

void ZLog::Put(const TString& time_string, Int_t level, const TString& prefix, const TString& message)
{
  LEVEL_CHECK(level);
  LEVEL_NAME(lvl_name, level);
  TString pim(prefix.EndsWith(" ") ? "" : " ");

  GMutexHolder _lck(mLoggerCond);
  mStream << time_string << " " << lvl_name << " " << prefix << pim << message << endl;
}

void ZLog::Form(Int_t level, const TString& prefix, const char* va_(fmt), ...)
{
  va_list ap;
  va_start(ap, va_(fmt));
  FormVA(GTime::ApproximateTime().ToDateTimeLocal(false), level, prefix, va_(fmt), ap);
  va_end(ap);
}

void ZLog::Form(const GTime& time, Int_t level, const TString& prefix, const char* va_(fmt), ...)
{
  va_list ap;
  va_start(ap, va_(fmt));
  FormVA(time.ToDateTimeLocal(false), level, prefix, va_(fmt), ap);
  va_end(ap);
}

void ZLog::Form(const TString& time_string, Int_t level, const TString& prefix, const char* va_(fmt), ...)
{
  LEVEL_CHECK(level);
  LEVEL_NAME(lvl_name, level);
  TString message;
  {
    va_list ap;
    va_start(ap, va_(fmt));
    message = GFormVA(va_(fmt), ap);
    va_end(ap);
  }
  TString pim(prefix.EndsWith(" ") ? "" : " ");

  GMutexHolder _lck(mLoggerCond);
  mStream << time_string << " " << lvl_name << " " << prefix << pim << message << endl;
}

void ZLog::FormVA(const GTime& time, Int_t level, const TString& prefix, const char* va_(fmt), va_list args)
{
  FormVA(time.ToDateTimeLocal(false), level, prefix, va_(fmt), args);
}

void ZLog::FormVA(const TString& time_string, Int_t level, const TString& prefix, const char* va_(fmt), va_list args)
{
  LEVEL_CHECK(level);
  LEVEL_NAME(lvl_name, level);
  TString message(GFormVA(va_(fmt), args));
  TString pim(prefix.EndsWith(" ") ? "" : " ");

  GMutexHolder _lck(mLoggerCond);
  mStream << time_string << " " << lvl_name << " " << prefix << pim << message << endl;
}


//==============================================================================
// ZLog::Helper
//==============================================================================

ZLog::Helper::Helper(ZLog* log, const TString& pfx) :
  m_log(log), m_prefix(pfx), m_level(L_Message)
{
  SetTime(GTime::ApproximateTime());
}

ZLog::Helper::Helper(ZLog* log, Int_t lvl, const TString& pfx) :
  m_log(log), m_prefix(pfx), m_level(lvl)
{
  SetTime(GTime::ApproximateTime());
}

ZLog::Helper::Helper(ZLog* log, const GTime& when, const TString& pfx) :
  m_log(log), m_prefix(pfx), m_level(L_Message)
{
  SetTime(when);
}

ZLog::Helper::Helper(ZLog* log, const GTime& when, Int_t lvl, const TString& pfx) :
  m_log(log), m_prefix(pfx), m_level(lvl)
{
  SetTime(when);
}

void ZLog::Helper::SetTime(const GTime& time)
{
  m_time = time;
  m_time_string = m_time.ToDateTimeLocal(false);
}

void ZLog::Helper::Put(const TString& message)
{
  if (m_log)
  {
    m_log->Put(m_time_string, m_level, m_prefix, message);
  }
}

void ZLog::Helper::Put(Int_t level, const TString& message)
{
  if (m_log)
  {
    m_log->Put(m_time_string, level, m_prefix, message);
  }
}

void ZLog::Helper::Form(const char* va_(fmt), ...)
{
  if (m_log)
  {
    va_list ap;
    va_start(ap, va_(fmt));
    m_log->FormVA(m_time_string, m_level, m_prefix, va_(fmt), ap);
    va_end(ap);
  }
}

void ZLog::Helper::Form(Int_t level, const char* va_(fmt), ...)
{
  if (m_log)
  {
    va_list ap;
    va_start(ap, va_(fmt));
    m_log->FormVA(m_time_string, level, m_prefix, va_(fmt), ap);
    va_end(ap);
  }
}
 ZLog.cxx:1
 ZLog.cxx:2
 ZLog.cxx:3
 ZLog.cxx:4
 ZLog.cxx:5
 ZLog.cxx:6
 ZLog.cxx:7
 ZLog.cxx:8
 ZLog.cxx:9
 ZLog.cxx:10
 ZLog.cxx:11
 ZLog.cxx:12
 ZLog.cxx:13
 ZLog.cxx:14
 ZLog.cxx:15
 ZLog.cxx:16
 ZLog.cxx:17
 ZLog.cxx:18
 ZLog.cxx:19
 ZLog.cxx:20
 ZLog.cxx:21
 ZLog.cxx:22
 ZLog.cxx:23
 ZLog.cxx:24
 ZLog.cxx:25
 ZLog.cxx:26
 ZLog.cxx:27
 ZLog.cxx:28
 ZLog.cxx:29
 ZLog.cxx:30
 ZLog.cxx:31
 ZLog.cxx:32
 ZLog.cxx:33
 ZLog.cxx:34
 ZLog.cxx:35
 ZLog.cxx:36
 ZLog.cxx:37
 ZLog.cxx:38
 ZLog.cxx:39
 ZLog.cxx:40
 ZLog.cxx:41
 ZLog.cxx:42
 ZLog.cxx:43
 ZLog.cxx:44
 ZLog.cxx:45
 ZLog.cxx:46
 ZLog.cxx:47
 ZLog.cxx:48
 ZLog.cxx:49
 ZLog.cxx:50
 ZLog.cxx:51
 ZLog.cxx:52
 ZLog.cxx:53
 ZLog.cxx:54
 ZLog.cxx:55
 ZLog.cxx:56
 ZLog.cxx:57
 ZLog.cxx:58
 ZLog.cxx:59
 ZLog.cxx:60
 ZLog.cxx:61
 ZLog.cxx:62
 ZLog.cxx:63
 ZLog.cxx:64
 ZLog.cxx:65
 ZLog.cxx:66
 ZLog.cxx:67
 ZLog.cxx:68
 ZLog.cxx:69
 ZLog.cxx:70
 ZLog.cxx:71
 ZLog.cxx:72
 ZLog.cxx:73
 ZLog.cxx:74
 ZLog.cxx:75
 ZLog.cxx:76
 ZLog.cxx:77
 ZLog.cxx:78
 ZLog.cxx:79
 ZLog.cxx:80
 ZLog.cxx:81
 ZLog.cxx:82
 ZLog.cxx:83
 ZLog.cxx:84
 ZLog.cxx:85
 ZLog.cxx:86
 ZLog.cxx:87
 ZLog.cxx:88
 ZLog.cxx:89
 ZLog.cxx:90
 ZLog.cxx:91
 ZLog.cxx:92
 ZLog.cxx:93
 ZLog.cxx:94
 ZLog.cxx:95
 ZLog.cxx:96
 ZLog.cxx:97
 ZLog.cxx:98
 ZLog.cxx:99
 ZLog.cxx:100
 ZLog.cxx:101
 ZLog.cxx:102
 ZLog.cxx:103
 ZLog.cxx:104
 ZLog.cxx:105
 ZLog.cxx:106
 ZLog.cxx:107
 ZLog.cxx:108
 ZLog.cxx:109
 ZLog.cxx:110
 ZLog.cxx:111
 ZLog.cxx:112
 ZLog.cxx:113
 ZLog.cxx:114
 ZLog.cxx:115
 ZLog.cxx:116
 ZLog.cxx:117
 ZLog.cxx:118
 ZLog.cxx:119
 ZLog.cxx:120
 ZLog.cxx:121
 ZLog.cxx:122
 ZLog.cxx:123
 ZLog.cxx:124
 ZLog.cxx:125
 ZLog.cxx:126
 ZLog.cxx:127
 ZLog.cxx:128
 ZLog.cxx:129
 ZLog.cxx:130
 ZLog.cxx:131
 ZLog.cxx:132
 ZLog.cxx:133
 ZLog.cxx:134
 ZLog.cxx:135
 ZLog.cxx:136
 ZLog.cxx:137
 ZLog.cxx:138
 ZLog.cxx:139
 ZLog.cxx:140
 ZLog.cxx:141
 ZLog.cxx:142
 ZLog.cxx:143
 ZLog.cxx:144
 ZLog.cxx:145
 ZLog.cxx:146
 ZLog.cxx:147
 ZLog.cxx:148
 ZLog.cxx:149
 ZLog.cxx:150
 ZLog.cxx:151
 ZLog.cxx:152
 ZLog.cxx:153
 ZLog.cxx:154
 ZLog.cxx:155
 ZLog.cxx:156
 ZLog.cxx:157
 ZLog.cxx:158
 ZLog.cxx:159
 ZLog.cxx:160
 ZLog.cxx:161
 ZLog.cxx:162
 ZLog.cxx:163
 ZLog.cxx:164
 ZLog.cxx:165
 ZLog.cxx:166
 ZLog.cxx:167
 ZLog.cxx:168
 ZLog.cxx:169
 ZLog.cxx:170
 ZLog.cxx:171
 ZLog.cxx:172
 ZLog.cxx:173
 ZLog.cxx:174
 ZLog.cxx:175
 ZLog.cxx:176
 ZLog.cxx:177
 ZLog.cxx:178
 ZLog.cxx:179
 ZLog.cxx:180
 ZLog.cxx:181
 ZLog.cxx:182
 ZLog.cxx:183
 ZLog.cxx:184
 ZLog.cxx:185
 ZLog.cxx:186
 ZLog.cxx:187
 ZLog.cxx:188
 ZLog.cxx:189
 ZLog.cxx:190
 ZLog.cxx:191
 ZLog.cxx:192
 ZLog.cxx:193
 ZLog.cxx:194
 ZLog.cxx:195
 ZLog.cxx:196
 ZLog.cxx:197
 ZLog.cxx:198
 ZLog.cxx:199
 ZLog.cxx:200
 ZLog.cxx:201
 ZLog.cxx:202
 ZLog.cxx:203
 ZLog.cxx:204
 ZLog.cxx:205
 ZLog.cxx:206
 ZLog.cxx:207
 ZLog.cxx:208
 ZLog.cxx:209
 ZLog.cxx:210
 ZLog.cxx:211
 ZLog.cxx:212
 ZLog.cxx:213
 ZLog.cxx:214
 ZLog.cxx:215
 ZLog.cxx:216
 ZLog.cxx:217
 ZLog.cxx:218
 ZLog.cxx:219
 ZLog.cxx:220
 ZLog.cxx:221
 ZLog.cxx:222
 ZLog.cxx:223
 ZLog.cxx:224
 ZLog.cxx:225
 ZLog.cxx:226
 ZLog.cxx:227
 ZLog.cxx:228
 ZLog.cxx:229
 ZLog.cxx:230
 ZLog.cxx:231
 ZLog.cxx:232
 ZLog.cxx:233
 ZLog.cxx:234
 ZLog.cxx:235
 ZLog.cxx:236
 ZLog.cxx:237
 ZLog.cxx:238
 ZLog.cxx:239
 ZLog.cxx:240
 ZLog.cxx:241
 ZLog.cxx:242
 ZLog.cxx:243
 ZLog.cxx:244
 ZLog.cxx:245
 ZLog.cxx:246
 ZLog.cxx:247
 ZLog.cxx:248
 ZLog.cxx:249
 ZLog.cxx:250
 ZLog.cxx:251
 ZLog.cxx:252
 ZLog.cxx:253
 ZLog.cxx:254
 ZLog.cxx:255
 ZLog.cxx:256
 ZLog.cxx:257
 ZLog.cxx:258
 ZLog.cxx:259
 ZLog.cxx:260
 ZLog.cxx:261
 ZLog.cxx:262
 ZLog.cxx:263
 ZLog.cxx:264
 ZLog.cxx:265
 ZLog.cxx:266
 ZLog.cxx:267
 ZLog.cxx:268
 ZLog.cxx:269
 ZLog.cxx:270
 ZLog.cxx:271
 ZLog.cxx:272
 ZLog.cxx:273
 ZLog.cxx:274
 ZLog.cxx:275
 ZLog.cxx:276
 ZLog.cxx:277
 ZLog.cxx:278
 ZLog.cxx:279
 ZLog.cxx:280
 ZLog.cxx:281
 ZLog.cxx:282
 ZLog.cxx:283
 ZLog.cxx:284
 ZLog.cxx:285
 ZLog.cxx:286
 ZLog.cxx:287
 ZLog.cxx:288
 ZLog.cxx:289
 ZLog.cxx:290
 ZLog.cxx:291
 ZLog.cxx:292
 ZLog.cxx:293
 ZLog.cxx:294
 ZLog.cxx:295
 ZLog.cxx:296
 ZLog.cxx:297
 ZLog.cxx:298
 ZLog.cxx:299
 ZLog.cxx:300
 ZLog.cxx:301
 ZLog.cxx:302
 ZLog.cxx:303
 ZLog.cxx:304
 ZLog.cxx:305
 ZLog.cxx:306
 ZLog.cxx:307
 ZLog.cxx:308
 ZLog.cxx:309
 ZLog.cxx:310
 ZLog.cxx:311
 ZLog.cxx:312
 ZLog.cxx:313
 ZLog.cxx:314
 ZLog.cxx:315
 ZLog.cxx:316
 ZLog.cxx:317
 ZLog.cxx:318
 ZLog.cxx:319
 ZLog.cxx:320
 ZLog.cxx:321
 ZLog.cxx:322
 ZLog.cxx:323
 ZLog.cxx:324
 ZLog.cxx:325
 ZLog.cxx:326
 ZLog.cxx:327
 ZLog.cxx:328
 ZLog.cxx:329
 ZLog.cxx:330
 ZLog.cxx:331
 ZLog.cxx:332
 ZLog.cxx:333
 ZLog.cxx:334
 ZLog.cxx:335
 ZLog.cxx:336
 ZLog.cxx:337
 ZLog.cxx:338
 ZLog.cxx:339
 ZLog.cxx:340
 ZLog.cxx:341
 ZLog.cxx:342
 ZLog.cxx:343
 ZLog.cxx:344
 ZLog.cxx:345
 ZLog.cxx:346
 ZLog.cxx:347
 ZLog.cxx:348
 ZLog.cxx:349
 ZLog.cxx:350
 ZLog.cxx:351
 ZLog.cxx:352
 ZLog.cxx:353
 ZLog.cxx:354
 ZLog.cxx:355