NCBI C++ ToolKit
ncbidiag.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbidiag.cpp 101898 2024-02-29 14:05:58Z gouriano $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Authors: Denis Vakatov et al.
27  *
28  * File Description:
29  * NCBI C++ diagnostic API
30  *
31  */
32 
33 
34 #include <ncbi_pch.hpp>
35 #include <common/ncbi_source_ver.h>
37 #include <common/ncbi_sanitizers.h>
38 #include <corelib/ncbiexpt.hpp>
39 #include <corelib/version.hpp>
40 #include <corelib/ncbi_process.hpp>
41 #include <corelib/ncbifile.hpp>
42 #include <corelib/syslog.hpp>
43 #include <corelib/error_codes.hpp>
44 #include <corelib/request_ctx.hpp>
46 #include <corelib/ncbi_strings.h>
48 #include <corelib/ncbiapp_api.hpp>
49 #include "ncbidiag_p.hpp"
50 #include "ncbisys.hpp"
51 #include <fcntl.h>
52 #include <stdlib.h>
53 #include <stack>
54 #include <atomic>
55 #include <thread>
56 #include <unordered_set>
57 #include <sstream>
58 
59 #if defined(NCBI_OS_UNIX)
60 # include <unistd.h>
61 # include <sys/utsname.h>
62 #endif
63 
64 #if defined(NCBI_OS_MSWIN)
65 # include <io.h>
66 #elif defined (NCBI_OS_DARWIN)
67 # include <crt_externs.h>
68 # define environ (*_NSGetEnviron())
69 #else
70 extern char** environ;
71 #endif
72 
73 
74 #define NCBI_USE_ERRCODE_X Corelib_Diag
75 
76 
78 
79 static bool s_DiagUseRWLock = true;
80 DEFINE_STATIC_MUTEX(s_DiagMutex);
81 DEFINE_STATIC_MUTEX(s_DiagPostMutex);
84 
85 DEFINE_STATIC_MUTEX(s_ApproveMutex);
86 
87 
88 void g_Diag_Use_RWLock(bool enable)
89 {
90  if (s_DiagUseRWLock == enable) return; // already switched
91  // Try to detect at least some dangerous situations.
92  // This does not guarantee safety since some thread may
93  // be waiting for lock while we switch to the new method.
94  if ( enable ) {
95  bool diag_unlocked = s_DiagMutex.TryLock();
96  // Mutex is locked - fail
97  _ASSERT(diag_unlocked);
98  if (!diag_unlocked) {
99  _TROUBLE;
100  NCBI_THROW(CCoreException, eCore,
101  "Cannot switch diagnostic to RW-lock - mutex is locked.");
102  }
103  s_DiagMutex.Unlock();
104  }
105  else {
106  // Switch from RW-lock to mutex
107  bool diag_unlocked = s_DiagRWLock->TryWriteLock();
108  // RW-lock is locked - fail
109  _ASSERT(diag_unlocked);
110  if (!diag_unlocked) {
111  _TROUBLE;
112  NCBI_THROW(CCoreException, eCore,
113  "Cannot switch diagnostic to mutex - RW-lock is locked.");
114  }
115  s_DiagRWLock->Unlock();
116  }
117  s_DiagUseRWLock = enable;
118 }
119 
120 
122 {
123 public:
124  enum ELockType {
125  eRead, // read lock
126  eWrite, // write lock (modifying flags etc.)
127  ePost // lock used by diag handlers to lock stream in Post()
128  };
129 
131  : m_UsedRWLock(false), m_LockType(locktype)
132  {
133  if (s_DiagUseRWLock) {
134  if (m_LockType == eRead) {
135  m_UsedRWLock = true;
136  s_DiagRWLock->ReadLock();
137  return;
138  }
139  if (m_LockType == eWrite) {
140  m_UsedRWLock = true;
141  s_DiagRWLock->WriteLock();
142  return;
143  }
144  // For ePost use normal mutex below.
145  }
146  if (m_LockType == ePost) {
147  s_DiagPostMutex.Lock();
148  }
149  else {
150  s_DiagMutex.Lock();
151  }
152  }
153 
155  {
156  if (m_UsedRWLock) {
157  s_DiagRWLock->Unlock();
158  }
159  else {
160  if (m_LockType == ePost) {
161  s_DiagPostMutex.Unlock();
162  }
163  else {
164  s_DiagMutex.Unlock();
165  }
166  }
167  }
168 
169 private:
172 };
173 
174 
175 static const char* kLogName_None = "NONE";
176 static const char* kLogName_Unknown = "UNKNOWN";
177 static const char* kLogName_Stdout = "STDOUT";
178 static const char* kLogName_Stderr = "STDERR";
179 static const char* kLogName_Stream = "STREAM";
180 static const char* kLogName_Memory = "MEMORY";
181 static const char* kLogName_Tee = "STDERR-TEE";
182 
183 
185 {
186 public:
188  virtual ~CDiagFileHandleHolder(void);
189 
190  int GetHandle(void) { return m_Handle; }
191 
192 private:
193  int m_Handle;
194 };
195 
196 
197 // Special diag handler for duplicating error log messages on stderr.
199 {
200 public:
201  CTeeDiagHandler(CDiagHandler* orig, bool own_orig);
202  virtual void Post(const SDiagMessage& mess);
203 
204  virtual void PostToConsole(const SDiagMessage& mess)
205  {
206  // Console manipulator ignores severity, so we have to always print
207  // the message to console and set NoTee flag to avoid duplicates.
209  const_cast<SDiagMessage&>(mess).m_NoTee = true;
210  }
211 
212  virtual string GetLogName(void)
213  {
214  return m_OrigHandler.get() ?
216  }
217  virtual void Reopen(TReopenFlags flags)
218  {
219  if ( m_OrigHandler.get() ) {
221  }
222  }
223 
225  {
226  return m_OrigHandler.get();
227  }
228 
229 private:
232 };
233 
234 
235 #if defined(NCBI_POSIX_THREADS) && defined(HAVE_PTHREAD_ATFORK)
236 
237 #include <unistd.h> // for pthread_atfork()
238 
239 extern "C" {
240  static void s_NcbiDiagPreFork(void)
241  {
242  s_DiagMutex.Lock();
243  }
244  static void s_NcbiDiagPostFork(void)
245  {
246  s_DiagMutex.Unlock();
247  }
248 }
249 
250 #endif
251 
252 
253 ///////////////////////////////////////////////////////
254 // Output format parameters
255 
256 // Use old output format if the flag is set
257 NCBI_PARAM_DECL(bool, Diag, Old_Post_Format);
258 NCBI_PARAM_DEF_EX(bool, Diag, Old_Post_Format, true, eParam_NoThread,
259  DIAG_OLD_POST_FORMAT);
260 static CSafeStatic<NCBI_PARAM_TYPE(Diag, Old_Post_Format)> s_OldPostFormat(
262 
263 // Auto-print context properties on set/change.
264 NCBI_PARAM_DECL(bool, Diag, AutoWrite_Context);
265 NCBI_PARAM_DEF_EX(bool, Diag, AutoWrite_Context, false, eParam_NoThread,
266  DIAG_AUTOWRITE_CONTEXT);
267 static CSafeStatic<NCBI_PARAM_TYPE(Diag, AutoWrite_Context)> s_AutoWrite_Context;
268 
269 // Print system TID rather than CThread::GetSelf()
270 NCBI_PARAM_DECL(bool, Diag, Print_System_TID);
271 NCBI_PARAM_DEF_EX(bool, Diag, Print_System_TID, false, eParam_NoThread,
272  DIAG_PRINT_SYSTEM_TID);
273 static CSafeStatic<NCBI_PARAM_TYPE(Diag, Print_System_TID)> s_PrintSystemTID;
274 
275 // Use assert() instead of abort() when printing fatal errors
276 // to show the assertion dialog and allow to choose the action
277 // (stop/debug/continue).
278 NCBI_PARAM_DECL(bool, Diag, Assert_On_Abort);
279 NCBI_PARAM_DEF_EX(bool, Diag, Assert_On_Abort, false, eParam_NoThread,
280  DIAG_ASSERT_ON_ABORT);
281 
282 // Limit log file size, rotate log when it reaches the limit.
283 NCBI_PARAM_DECL(long, Diag, Log_Size_Limit);
284 NCBI_PARAM_DEF_EX(long, Diag, Log_Size_Limit, 0, eParam_NoThread,
285  DIAG_LOG_SIZE_LIMIT);
286 static CSafeStatic<NCBI_PARAM_TYPE(Diag, Log_Size_Limit)> s_LogSizeLimit;
287 
288 // Limit max line length, zero = no limit (default).
289 NCBI_PARAM_DECL(size_t, Diag, Max_Line_Length);
290 NCBI_PARAM_DEF_EX(size_t, Diag, Max_Line_Length, 0, eParam_NoThread,
291  DIAG_MAX_LINE_LENGTH);
292 static CSafeStatic<NCBI_PARAM_TYPE(Diag, Max_Line_Length)> s_MaxLineLength;
293 
294 
295 ///////////////////////////////////////////////////////
296 // Output rate control parameters
297 
299 {
300 public:
301  typedef unsigned int TValue;
304 
305  operator TValue(void) const
306  {
307  return m_Value;
308  }
309 
310  void Set(TValue val)
311  {
312  m_Value = val;
313  }
314 
315 private:
317 };
318 
319 
321 {
322  lim.Set(kMax_UInt);
323  string s;
324  getline(in, s);
325  if ( !NStr::EqualNocase(s, "off") ) {
326  lim.Set(NStr::StringToNumeric<CLogRateLimit::TValue>(s));
327  }
328  return in;
329 }
330 
331 
332 // Need CSafeStatic_Proxy<> instance for CLogRateLimit to allow static
333 // initialization of default values with unsigned int.
335 
336 
337 // AppLog limit per period
338 NCBI_PARAM_DECL(CLogRateLimit, Diag, AppLog_Rate_Limit);
339 NCBI_PARAM_DEF_EX(CLogRateLimit, Diag, AppLog_Rate_Limit, 50000,
340  eParam_NoThread, DIAG_APPLOG_RATE_LIMIT);
341 static CSafeStatic<NCBI_PARAM_TYPE(Diag, AppLog_Rate_Limit)> s_AppLogRateLimit;
342 
343 // AppLog period, sec
344 NCBI_PARAM_DECL(unsigned int, Diag, AppLog_Rate_Period);
345 NCBI_PARAM_DEF_EX(unsigned int, Diag, AppLog_Rate_Period, 10, eParam_NoThread,
346  DIAG_APPLOG_RATE_PERIOD);
347 static CSafeStatic<NCBI_PARAM_TYPE(Diag, AppLog_Rate_Period)> s_AppLogRatePeriod;
348 
349 // ErrLog limit per period
350 NCBI_PARAM_DECL(CLogRateLimit, Diag, ErrLog_Rate_Limit);
351 NCBI_PARAM_DEF_EX(CLogRateLimit, Diag, ErrLog_Rate_Limit, 5000,
352  eParam_NoThread, DIAG_ERRLOG_RATE_LIMIT);
353 static CSafeStatic<NCBI_PARAM_TYPE(Diag, ErrLog_Rate_Limit)> s_ErrLogRateLimit;
354 
355 // ErrLog period, sec
356 NCBI_PARAM_DECL(unsigned int, Diag, ErrLog_Rate_Period);
357 NCBI_PARAM_DEF_EX(unsigned int, Diag, ErrLog_Rate_Period, 1, eParam_NoThread,
358  DIAG_ERRLOG_RATE_PERIOD);
359 static CSafeStatic<NCBI_PARAM_TYPE(Diag, ErrLog_Rate_Period)> s_ErrLogRatePeriod;
360 
361 // TraceLog limit per period
362 NCBI_PARAM_DECL(CLogRateLimit, Diag, TraceLog_Rate_Limit);
363 NCBI_PARAM_DEF_EX(CLogRateLimit, Diag, TraceLog_Rate_Limit, 5000,
364  eParam_NoThread, DIAG_TRACELOG_RATE_LIMIT);
365 static CSafeStatic<NCBI_PARAM_TYPE(Diag, TraceLog_Rate_Limit)> s_TraceLogRateLimit;
366 
367 // TraceLog period, sec
368 NCBI_PARAM_DECL(unsigned int, Diag, TraceLog_Rate_Period);
369 NCBI_PARAM_DEF_EX(unsigned int, Diag, TraceLog_Rate_Period, 1, eParam_NoThread,
370  DIAG_TRACELOG_RATE_PERIOD);
371 static CSafeStatic<NCBI_PARAM_TYPE(Diag, TraceLog_Rate_Period)> s_TraceLogRatePeriod;
372 
373 // Duplicate messages to STDERR
374 NCBI_PARAM_DECL(bool, Diag, Tee_To_Stderr);
375 NCBI_PARAM_DEF_EX(bool, Diag, Tee_To_Stderr, false, eParam_NoThread,
376  DIAG_TEE_TO_STDERR);
377 typedef NCBI_PARAM_TYPE(Diag, Tee_To_Stderr) TTeeToStderr;
378 
379 // Minimum severity of the messages duplicated to STDERR
380 NCBI_PARAM_ENUM_DECL(EDiagSev, Diag, Tee_Min_Severity);
381 NCBI_PARAM_ENUM_ARRAY(EDiagSev, Diag, Tee_Min_Severity)
382 {
383  {"Info", eDiag_Info},
384  {"Warning", eDiag_Warning},
385  {"Error", eDiag_Error},
386  {"Critical", eDiag_Critical},
387  {"Fatal", eDiag_Fatal},
388  {"Trace", eDiag_Trace}
389 };
390 
392 #if defined(NDEBUG)
393  eDiag_Error;
394 #else
396 #endif
397 
398 NCBI_PARAM_ENUM_DEF_EX(EDiagSev, Diag, Tee_Min_Severity,
400  eParam_NoThread, DIAG_TEE_MIN_SEVERITY);
401 
402 
403 NCBI_PARAM_DECL(size_t, Diag, Collect_Limit);
404 NCBI_PARAM_DEF_EX(size_t, Diag, Collect_Limit, 1000, eParam_NoThread,
405  DIAG_COLLECT_LIMIT);
406 
407 
409 NCBI_PARAM_DEF_EX(bool, Log, Truncate, false, eParam_NoThread, LOG_TRUNCATE);
410 
411 
412 NCBI_PARAM_DECL(bool, Log, NoCreate);
413 NCBI_PARAM_DEF_EX(bool, Log, NoCreate, false, eParam_NoThread, LOG_NOCREATE);
414 
415 
416 // Logging of environment variables: space separated list of names which
417 // should be logged after app start and after each request start.
418 NCBI_PARAM_DECL(string, Log, LogEnvironment);
419 NCBI_PARAM_DEF_EX(string, Log, LogEnvironment, "",
421  DIAG_LOG_ENVIRONMENT);
422 
423 
424 // Logging of registry values: space separated list of 'section:name' strings.
425 NCBI_PARAM_DECL(string, Log, LogRegistry);
426 NCBI_PARAM_DEF_EX(string, Log, LogRegistry, "",
428  DIAG_LOG_REGISTRY);
429 
430 
431 // Turn off all applog messages (start/stop, request start/stop, extra).
432 NCBI_PARAM_DECL(bool, Diag, Disable_AppLog_Messages);
433 NCBI_PARAM_DEF_EX(bool, Diag, Disable_AppLog_Messages, false, eParam_NoThread,
434  DIAG_DISABLE_APPLOG_MESSAGES);
435 static CSafeStatic<NCBI_PARAM_TYPE(Diag, Disable_AppLog_Messages)> s_DisableAppLog;
436 
437 
438 static bool s_FinishedSetupDiag = false;
439 
440 
441 ///////////////////////////////////////////////////////
442 // CDiagContextThreadData::
443 
444 
445 /// Thread local context data stored in TLS
447 {
448 public:
451 
452  /// Get current request context.
454  /// Set request context. If NULL, switches the current thread
455  /// to its default request context.
457 
459 
460  /// Request id
463  NCBI_DEPRECATED void IncRequestId(void);
464 
465  /// Get request timer, create if not exist yet
467  /// Get request timer or null
469  /// Delete request timer
471 
472  /// Diag buffer
473  CDiagBuffer& GetDiagBuffer(void) { return *m_DiagBuffer; }
474 
475  /// Get diag context data for the current thread
477 
478  /// Thread ID
479  typedef Uint8 TTID;
480 
481  /// Get cached thread ID
482  TTID GetTID(void) const { return m_TID; }
483 
484  /// Get thread post number
486 
487  void AddCollectGuard(CDiagCollectGuard* guard);
490 
491  void CollectDiagMessage(const SDiagMessage& mess);
492 
493 private:
496 
497  // Guards override the global post level and define severity
498  // for collecting messages.
499  typedef list<CDiagCollectGuard*> TCollectGuards;
500 
501  // Collected diag messages
502  typedef list<SDiagMessage> TDiagCollection;
503 
504  unique_ptr<CDiagBuffer> m_DiagBuffer; // Thread's diag buffer
505  TTID m_TID; // Cached thread ID
506  TCount m_ThreadPostNumber; // Number of posted messages
509  size_t m_DiagCollectionSize; // cached size of m_DiagCollection
511  CRef<CRequestContext> m_DefaultRequestCtx; // Default request context
512 };
513 
514 
516 {
517  // the severities will be adjusted by x_Init()
519 }
520 
521 
523 {
524  // the severities will be adjusted by x_Init()
525  x_Init(eDiag_Critical, print_severity, eDiscard);
526 }
527 
528 
530  EDiagSev collect_severity,
531  EAction action)
532 {
533  // the severities will be adjusted by x_Init()
534  x_Init(print_severity, collect_severity, action);
535 }
536 
537 
539  EDiagSev collect_severity,
540  EAction action)
541 {
542  // Get current print severity
543  EDiagSev psev, csev;
544  CDiagContextThreadData& thr_data =
546  if ( thr_data.GetCollectGuard() ) {
547  psev = thr_data.GetCollectGuard()->GetPrintSeverity();
548  csev = thr_data.GetCollectGuard()->GetCollectSeverity();
549  }
550  else {
551  psev = CDiagBuffer::sm_PostSeverity;
552  csev = psev;
553  }
554  psev = CompareDiagPostLevel(psev, print_severity) > 0
555  ? psev : print_severity;
556  csev = CompareDiagPostLevel(csev, collect_severity) < 0
557  ? csev : collect_severity;
558 
561  m_PrintSev = psev;
562  m_CollectSev = csev;
563  m_SeverityCap = csev;
564  m_Action = action;
565  thr_data.AddCollectGuard(this);
566 }
567 
568 
570 {
571  Release();
572 }
573 
574 
576 {
578  thr_data.RemoveCollectGuard(this);
579 }
580 
581 
583 {
584  SetAction(action);
585  Release();
586 }
587 
588 
590 {
591  if ( CompareDiagPostLevel(m_PrintSev, sev) < 0 ) {
592  m_PrintSev = sev;
593  }
594 }
595 
596 
598 {
599  if ( CompareDiagPostLevel(m_CollectSev, sev) < 0 ) {
600  m_CollectSev = sev;
601  }
602 }
603 
604 
605 ///////////////////////////////////////////////////////
606 // Static variables for Trace and Post filters
607 
610 
611 
612 // Analogue to strstr.
613 // Returns a pointer to the last occurrence of a search string in a string
614 const char*
615 str_rev_str(const char* begin_str, const char* end_str, const char* str_search)
616 {
617  if (begin_str == NULL)
618  return NULL;
619  if (end_str == NULL)
620  return NULL;
621  if (str_search == NULL)
622  return NULL;
623 
624  const char* search_char = str_search + strlen(str_search);
625  const char* cur_char = end_str;
626 
627  do {
628  --search_char;
629  do {
630  --cur_char;
631  } while(*cur_char != *search_char && cur_char != begin_str);
632  if (*cur_char != *search_char)
633  return NULL;
634  }
635  while (search_char != str_search);
636 
637  return cur_char;
638 }
639 
640 
641 
642 /////////////////////////////////////////////////////////////////////////////
643 /// CDiagCompileInfo::
644 
646  : m_File(""),
647  m_Module(""),
648  m_Line(0),
649  m_CurrFunctName(0),
650  m_Parsed(false),
651  m_ClassSet(false)
652 {
653 }
654 
656  int line,
657  const char* curr_funct,
658  const char* module)
659  : m_File(file),
660  m_Module(""),
661  m_Line(line),
662  m_CurrFunctName(curr_funct),
663  m_Parsed(false),
664  m_ClassSet(false)
665 {
666  if (!file) {
667  m_File = "";
668  return;
669  }
670  if (!module)
671  return;
672  if ( 0 != strcmp(module, "NCBI_MODULE") && x_NeedModule() ) {
673  m_Module = module;
674  }
675 }
676 
677 
679  int line,
680  const string& curr_funct,
681  const string& module)
682  : m_File(""),
683  m_Module(""),
684  m_Line(line),
685  m_CurrFunctName(""),
686  m_Parsed(false),
687  m_ClassSet(false)
688 {
689  SetFile(file);
690  if ( m_File && !module.empty() && x_NeedModule() ) {
691  SetModule(module);
692  }
693  SetFunction(curr_funct);
694 }
695 
696 
698 {
699  // Check for a file extension without creating of temporary string objects
700  const char* cur_extension = strrchr(m_File, '.');
701  if (cur_extension == NULL)
702  return false;
703 
704  if (*(cur_extension + 1) != '\0') {
705  ++cur_extension;
706  } else {
707  return false;
708  }
709 
710  return strcmp(cur_extension, "cpp") == 0 ||
711  strcmp(cur_extension, "C") == 0 ||
712  strcmp(cur_extension, "c") == 0 ||
713  strcmp(cur_extension, "cxx") == 0;
714 }
715 
716 
718 {
719 }
720 
721 
722 void CDiagCompileInfo::SetFile(const string& file)
723 {
724  m_StrFile = file;
725  m_File = m_StrFile.c_str();
726 }
727 
728 
729 void CDiagCompileInfo::SetModule(const string& module)
730 {
731  m_StrModule = module;
732  m_Module = m_StrModule.c_str();
733 }
734 
735 
737 {
738  m_Line = line;
739 }
740 
741 
742 void CDiagCompileInfo::SetFunction(const string& func)
743 {
744  m_Parsed = false;
745  m_StrCurrFunctName = func;
746  if (m_StrCurrFunctName.find(')') == NPOS) {
747  m_StrCurrFunctName += "()";
748  }
750  m_FunctName.clear();
751  if ( !m_ClassSet ) {
752  m_ClassName.clear();
753  }
754 }
755 
756 
757 void CDiagCompileInfo::SetClass(const string& cls)
758 {
759  m_ClassName = cls;
760  m_ClassSet = true;
761 }
762 
763 
764 // Skip matching l/r separators, return the last char before them
765 // or null if the separators are unbalanced.
766 const char* find_match(char lsep,
767  char rsep,
768  const char* start,
769  const char* stop)
770 {
771  if (*(stop - 1) != rsep) return stop;
772  int balance = 1;
773  const char* pos = stop - 2;
774  for (; pos > start; pos--) {
775  if (*pos == rsep) {
776  balance++;
777  }
778  else if (*pos == lsep) {
779  if (--balance == 0) break;
780  }
781  }
782  return (pos <= start) ? NULL : pos;
783 }
784 
785 
786 void
788 {
789  m_Parsed = true;
790  if (!m_CurrFunctName || !(*m_CurrFunctName)) {
791  return;
792  }
793  // Parse curr_funct
794 
795  // Skip function arguments
796  size_t len = strlen(m_CurrFunctName);
797  const char* end_str = find_match('(', ')',
799  m_CurrFunctName + len);
800  if (end_str == m_CurrFunctName + len) {
801  // Missing '('
802  return;
803  }
804  if ( end_str ) {
805  // Skip template arguments
806  end_str = find_match('<', '>', m_CurrFunctName, end_str);
807  }
808  if ( !end_str ) {
809  return;
810  }
811  // Get a function/method name
812  const char* start_str = NULL;
813 
814  // Get a function start position.
815  const char* start_str_tmp =
816  str_rev_str(m_CurrFunctName, end_str, "::");
817  bool has_class = start_str_tmp != NULL;
818  if (start_str_tmp != NULL) {
819  start_str = start_str_tmp + 2;
820  } else {
821  start_str_tmp = str_rev_str(m_CurrFunctName, end_str, " ");
822  if (start_str_tmp != NULL) {
823  start_str = start_str_tmp + 1;
824  }
825  }
826 
827  const char* cur_funct_name =
828  (start_str == NULL ? m_CurrFunctName : start_str);
829  while (cur_funct_name && *cur_funct_name &&
830  (*cur_funct_name == '*' || *cur_funct_name == '&')) {
831  ++cur_funct_name;
832  }
833  size_t cur_funct_name_len = end_str - cur_funct_name;
834  m_FunctName = string(cur_funct_name, cur_funct_name_len);
835 
836  // Get a class name
837  if (has_class && !m_ClassSet) {
838  end_str = find_match('<', '>', m_CurrFunctName, start_str - 2);
839  start_str = str_rev_str(m_CurrFunctName, end_str, " ");
840  const char* cur_class_name =
841  (start_str == NULL ? m_CurrFunctName : start_str + 1);
842  while (cur_class_name && *cur_class_name &&
843  (*cur_class_name == '*' || *cur_class_name == '&')) {
844  ++cur_class_name;
845  }
846  size_t cur_class_name_len = end_str - cur_class_name;
847  m_ClassName = string(cur_class_name, cur_class_name_len);
848  }
849 }
850 
851 
852 
853 ///////////////////////////////////////////////////////
854 // CDiagRecycler::
855 
857 public:
859  {
860 #if defined(NCBI_POSIX_THREADS) && defined(HAVE_PTHREAD_ATFORK)
861  pthread_atfork(s_NcbiDiagPreFork, // before
862  s_NcbiDiagPostFork, // after in parent
863  s_NcbiDiagPostFork); // after in child
864 #endif
865  }
867  {
868  SetDiagHandler(0, false);
869  SetDiagErrCodeInfo(0, false);
870  }
871 };
872 
874 
875 
876 // Helper function to check if applog severity lock is set and
877 // return the proper printable severity.
878 
880 {
881  if ( !CDiagContext::IsApplogSeverityLocked() ) return sev;
882  return CompareDiagPostLevel(sev, eDiag_Warning) < 0
883  ? sev : eDiag_Warning;
884 }
885 
886 
887 inline Uint8 s_GetThreadId(void)
888 {
889  if (s_PrintSystemTID->Get()) {
890  return (Uint8)GetCurrentThreadSystemID(); // GCC 3.4.6 gives warning - ignore it.
891  } else {
892  return CThread::GetSelf();
893  }
894 }
895 
896 
903 };
904 
906 #define USE_TLS_DATA_CACHE
907 #ifdef USE_TLS_DATA_CACHE
909 #endif
910 
911 
913 {
915 }
916 
917 
919  : m_DiagBuffer(new CDiagBuffer),
920  m_TID(s_GetThreadId()),
921  m_ThreadPostNumber(0),
922  m_DiagCollectionSize(0)
923 {
924  // Default context should auto-reset on request start.
927 }
928 
929 
931 {
932 #ifdef USE_TLS_DATA_CACHE
933  if ( s_ThreadDataCache == this ) {
934  s_ThreadDataCache = 0;
935  }
936 #endif
937 }
938 
939 
941  void* /*cleanup_data*/)
942 {
943  if ( CThread::IsMain() ) {
944  // Copy properties from the main thread's TLS to the global properties.
946  // Print stop message.
949  }
950  }
951  s_ThreadDataState = eDeinitialized; // re-enable protection
952  delete value;
953 }
954 
955 
957 {
958  // If any of this method's direct or indirect callees attempted to
959  // report a (typically fatal) error, the result would ordinarily
960  // be infinite recursion resulting in an undignified crash. The
961  // business with s_ThreadDataState allows the program to exit
962  // (relatively) gracefully in such cases.
963  //
964  // In principle, such an event could happen at any stage; in
965  // practice, however, the first call involves a superset of most
966  // following calls' actions, at least until deep program
967  // finalization. Moreover, attempting to catch bad calls
968  // mid-execution would both add overhead and open up uncatchable
969  // opportunities for inappropriate recursion.
970 
971  #ifdef USE_TLS_DATA_CACHE
973  return *data;
974  }
975 #endif
976 
977 
979  // Avoid false positives, while also taking care not to call
980  // anything that might itself produce diagnostics.
981  EThreadDataState thread_data_state = s_ThreadDataState; // for Clang10
982  switch (thread_data_state) {
983  case eInitialized:
984  break;
985 
986  case eUninitialized:
988  break;
989 
990  case eInitializing:
991  cerr << "FATAL ERROR: inappropriate recursion initializing NCBI"
992  " diagnostic framework." << endl;
993  Abort();
994  break;
995 
996  case eDeinitialized:
998  break;
999 
1000  case eReinitializing:
1001  cerr << "FATAL ERROR: NCBI diagnostic framework no longer"
1002  " initialized." << endl;
1003  Abort();
1004  break;
1005  }
1006  }
1007 
1009  s_ThreadData(nullptr, CSafeStaticLifeSpan(CSafeStaticLifeSpan::eLifeSpan_Long, 1));
1010 
1011  // Deliberate leak for 'data'-- for both cases:
1012  // GetValue() and new CDiagContextThreadData.
1014 
1015  CDiagContextThreadData* data = s_ThreadData.GetValue();
1016  if ( !data ) {
1017  // Cleanup data set to null for any thread except the main one.
1018  // This value is used as a flag to copy threads' properties to global
1019  // upon TLS cleanup.
1022  !CThread::IsMain() ? 0 : (void*)(1),
1025  }
1026 
1027 #ifdef USE_TLS_DATA_CACHE
1029 #endif
1030  return *data;
1031 }
1032 
1033 
1035 {
1037  return *m_RequestCtx;
1038 }
1039 
1040 
1041 static const Uint8 kOwnerTID_None = Uint8(-1);
1042 
1044 {
1045  if (m_RequestCtx) {
1046  // If pointers are the same (e.g. consecutive calls with the same ctx)
1047  if (ctx == m_RequestCtx.GetPointer()) {
1048  return;
1049  }
1050 
1051  // Reset TID in the context.
1053  }
1054 
1055  if (!ctx) {
1057  return;
1058  }
1059 
1060  m_RequestCtx = ctx;
1061  if (!m_RequestCtx->GetReadOnly()) {
1063  // Save current TID in the context.
1065  }
1066  else if (m_RequestCtx->m_OwnerTID != m_TID) {
1067  ERR_POST_X_ONCE(29,
1068  "Using the same CRequestContext in multiple threads is unsafe!"
1069  << CStackTrace());
1070  _TROUBLE;
1071  }
1072  }
1073  else {
1074  // Read-only contexts should not remember owner thread.
1076  }
1077 }
1078 
1079 
1082 {
1083  return inc == ePostNumber_Increment ?
1085 }
1086 
1087 
1089 {
1090  m_CollectGuards.push_front(guard);
1091 }
1092 
1093 
1095 {
1096  TCollectGuards::iterator itg = find(
1097  m_CollectGuards.begin(), m_CollectGuards.end(), guard);
1098  if (itg == m_CollectGuards.end()) {
1099  return; // The guard has been already released
1100  }
1101  m_CollectGuards.erase(itg);
1102  auto action = guard->GetAction();
1103  unique_ptr<CDiagLock> lock;
1104  if (action == CDiagCollectGuard::ePrintCapped) {
1105  lock.reset(new CDiagLock(CDiagLock::eRead));
1106  EDiagSev cap = guard->GetSeverityCap();
1107  auto start = guard->GetStartingPoint();
1109  if (itc->m_ThrPost >= start
1110  && CompareDiagPostLevel(itc->m_Severity, cap) > 0) {
1111  itc->m_Severity = cap;
1112  }
1113  }
1114  action = CDiagCollectGuard::ePrint;
1115  }
1116  if ( !m_CollectGuards.empty() ) {
1117  return;
1118  // Previously printing was done for each guard, discarding - only for
1119  // the last guard.
1120  }
1121  // If this is the last guard, perform its action
1122  if (lock.get() == nullptr) {
1123  lock.reset(new CDiagLock(CDiagLock::eRead));
1124  }
1125  if (action == CDiagCollectGuard::ePrint) {
1127  if ( handler ) {
1129  if ((itc->m_Flags & eDPF_IsConsole) != 0) {
1130  // Print all messages to console
1131  handler->PostToConsole(*itc);
1132  }
1133  // Make sure only messages with the severity above allowed
1134  // are printed to normal log.
1136  guard->GetCollectSeverity());
1137  bool allow_trace = post_sev == eDiag_Trace;
1138  if (itc->m_Severity == eDiag_Trace && !allow_trace) {
1139  continue; // trace is disabled
1140  }
1141  if (itc->m_Severity < post_sev) {
1142  continue;
1143  }
1144  handler->Post(*itc);
1145  }
1146  size_t discarded = m_DiagCollectionSize - m_DiagCollection.size();
1147  if (discarded > 0) {
1148  ERR_POST_X(18, Warning << "Discarded " << discarded <<
1149  " messages due to collection limit. Set "
1150  "DIAG_COLLECT_LIMIT to increase the limit.");
1151  }
1152  }
1153  }
1154  m_DiagCollection.clear();
1156 }
1157 
1158 
1160 {
1161  return m_CollectGuards.empty() ? NULL : m_CollectGuards.front();
1162 }
1163 
1164 
1166 {
1167  static CSafeStatic<NCBI_PARAM_TYPE(Diag, Collect_Limit)> s_DiagCollectLimit;
1168  if (m_DiagCollectionSize >= s_DiagCollectLimit->Get()) {
1169  m_DiagCollection.erase(m_DiagCollection.begin());
1170  }
1171  m_DiagCollection.push_back(mess);
1173 }
1174 
1175 
1178 {
1179  return GetRequestContext().GetRequestID();
1180 }
1181 
1182 
1184 {
1186 }
1187 
1188 
1190 {
1192 }
1193 
1194 
1196 {
1198 }
1199 
1200 
1201 extern void SetDiagRequestId(Uint8 id)
1202 {
1204 }
1205 
1206 
1207 ///////////////////////////////////////////////////////
1208 // CDiagContext::
1209 
1210 
1211 // AppState formatting/parsing
1212 static const char* s_AppStateStr[] = {
1213  "NS", "PB", "P", "PE", "RB", "R", "RE"
1214 };
1215 
1216 static const char* s_LegacyAppStateStr[] = {
1217  "AB", "A", "AE"
1218 };
1219 
1221 {
1222  return s_AppStateStr[state];
1223 }
1224 
1226 {
1227  for (int st = (int)eDiagAppState_AppBegin;
1228  st <= eDiagAppState_RequestEnd; st++) {
1229  if (state == s_AppStateStr[st]) {
1230  return (EDiagAppState)st;
1231  }
1232  }
1233  // Backward compatibility - allow to use 'A' instead of 'P'
1234  for (int st = (int)eDiagAppState_AppBegin;
1235  st <= eDiagAppState_AppEnd; st++) {
1236  if (state == s_LegacyAppStateStr[st - 1]) {
1237  return (EDiagAppState)st;
1238  }
1239  }
1240 
1241  // Throw to notify caller about invalid app state.
1242  NCBI_THROW(CException, eUnknown, "Invalid EDiagAppState value");
1243  /*NOTREACHED*/
1244  return eDiagAppState_NotSet;
1245 }
1246 
1247 
1248 NCBI_PARAM_DECL(bool, Diag, UTC_Timestamp);
1249 NCBI_PARAM_DEF_EX(bool, Diag, UTC_Timestamp, false,
1250  eParam_NoThread, DIAG_UTC_TIMESTAMP);
1251 
1252 
1253 static CTime s_GetFastTime(void)
1254 {
1255  static CSafeStatic<NCBI_PARAM_TYPE(Diag, UTC_Timestamp)> s_UtcTimestamp;
1256  return (s_UtcTimestamp->Get() && !CDiagContext::IsApplogSeverityLocked()) ?
1258 }
1259 
1260 
1262 {
1263  SDiagMessageData(void);
1265 
1266  string m_Message;
1267  string m_File;
1268  string m_Module;
1269  string m_Class;
1270  string m_Function;
1271  string m_Prefix;
1272  string m_ErrText;
1273 
1276 
1277  // If the following properties are not set, take them from DiagContext.
1278  string m_Host;
1279  string m_Client;
1280  string m_Session;
1281  string m_AppName;
1283 };
1284 
1285 
1287  : m_UID(0),
1288  m_Time(s_GetFastTime()),
1289  m_AppState(eDiagAppState_NotSet)
1290 {
1291 }
1292 
1293 
1296 
1297 
1299  : m_UID(0),
1300  m_Host(new CEncodedString),
1301  m_Username(new CEncodedString),
1302  m_AppName(new CEncodedString),
1303  m_AppNameSet(false),
1304  m_LoggedHitId(false),
1305  m_ExitCode(0),
1306  m_ExitCodeSet(false),
1307  m_ExitSig(0),
1308  m_AppState(eDiagAppState_AppBegin),
1309  m_StopWatch(new CStopWatch(CStopWatch::eStart)),
1310  m_MaxMessages(100), // limit number of collected messages to 100
1311  m_AppLogRC(new CRequestRateControl(
1312  GetLogRate_Limit(eLogRate_App),
1313  CTimeSpan((long)GetLogRate_Period(eLogRate_App)),
1314  CTimeSpan((long)0),
1315  CRequestRateControl::eErrCode,
1316  CRequestRateControl::eDiscrete)),
1317  m_ErrLogRC(new CRequestRateControl(
1318  GetLogRate_Limit(eLogRate_Err),
1319  CTimeSpan((long)GetLogRate_Period(eLogRate_Err)),
1320  CTimeSpan((long)0),
1321  CRequestRateControl::eErrCode,
1322  CRequestRateControl::eDiscrete)),
1323  m_TraceLogRC(new CRequestRateControl(
1324  GetLogRate_Limit(eLogRate_Trace),
1325  CTimeSpan((long)GetLogRate_Period(eLogRate_Trace)),
1326  CTimeSpan((long)0),
1327  CRequestRateControl::eErrCode,
1328  CRequestRateControl::eDiscrete)),
1329  m_AppLogSuspended(false),
1330  m_ErrLogSuspended(false),
1331  m_TraceLogSuspended(false)
1332 {
1333  sm_Instance = this;
1334 }
1335 
1336 
1338 {
1339  sm_Instance = NULL;
1340 }
1341 
1342 
1344 {
1345  CMutexGuard lock(s_ApproveMutex);
1348  CTimeSpan((long)0),
1353  CTimeSpan((long)0),
1358  CTimeSpan((long)0),
1361  m_AppLogSuspended = false;
1362  m_ErrLogSuspended = false;
1363  m_TraceLogSuspended = false;
1364 }
1365 
1366 
1368 {
1369  switch ( type ) {
1370  case eLogRate_App:
1371  return s_AppLogRateLimit->Get();
1372  case eLogRate_Err:
1373  return s_ErrLogRateLimit->Get();
1374  case eLogRate_Trace:
1375  default:
1376  return s_TraceLogRateLimit->Get();
1377  }
1378 }
1379 
1381 {
1382  CMutexGuard lock(s_ApproveMutex);
1383  switch ( type ) {
1384  case eLogRate_App:
1385  s_AppLogRateLimit->Set(limit);
1386  if ( m_AppLogRC.get() ) {
1387  m_AppLogRC->Reset(limit,
1389  CTimeSpan((long)0),
1392  }
1393  m_AppLogSuspended = false;
1394  break;
1395  case eLogRate_Err:
1396  s_ErrLogRateLimit->Set(limit);
1397  if ( m_ErrLogRC.get() ) {
1398  m_ErrLogRC->Reset(limit,
1400  CTimeSpan((long)0),
1403  }
1404  m_ErrLogSuspended = false;
1405  break;
1406  case eLogRate_Trace:
1407  default:
1408  s_TraceLogRateLimit->Set(limit);
1409  if ( m_TraceLogRC.get() ) {
1410  m_TraceLogRC->Reset(limit,
1412  CTimeSpan((long)0),
1415  }
1416  m_TraceLogSuspended = false;
1417  break;
1418  }
1419 }
1420 
1422 {
1423  switch ( type ) {
1424  case eLogRate_App:
1425  return s_AppLogRatePeriod->Get();
1426  case eLogRate_Err:
1427  return s_ErrLogRatePeriod->Get();
1428  case eLogRate_Trace:
1429  default:
1430  return s_TraceLogRatePeriod->Get();
1431  }
1432 }
1433 
1435 {
1436  CMutexGuard lock(s_ApproveMutex);
1437  switch ( type ) {
1438  case eLogRate_App:
1439  s_AppLogRatePeriod->Set(period);
1440  if ( m_AppLogRC.get() ) {
1442  CTimeSpan((long)period),
1443  CTimeSpan((long)0),
1446  }
1447  m_AppLogSuspended = false;
1448  break;
1449  case eLogRate_Err:
1450  s_ErrLogRatePeriod->Set(period);
1451  if ( m_ErrLogRC.get() ) {
1453  CTimeSpan((long)period),
1454  CTimeSpan((long)0),
1457  }
1458  m_ErrLogSuspended = false;
1459  break;
1460  case eLogRate_Trace:
1461  default:
1462  s_TraceLogRatePeriod->Set(period);
1463  if ( m_TraceLogRC.get() ) {
1465  CTimeSpan((long)period),
1466  CTimeSpan((long)0),
1469  }
1470  m_TraceLogSuspended = false;
1471  break;
1472  }
1473 }
1474 
1475 
1477  bool* show_warning)
1478 {
1479  bool approved = true;
1480  if ( IsSetDiagPostFlag(eDPF_AppLog, msg.m_Flags) ) {
1481  if ( m_AppLogRC->IsEnabled() ) {
1482  CMutexGuard lock(s_ApproveMutex);
1483  approved = m_AppLogRC->Approve();
1484  }
1485  if ( approved ) {
1486  m_AppLogSuspended = false;
1487  }
1488  else {
1489  *show_warning = !m_AppLogSuspended.exchange(true);
1490  }
1491  }
1492  else {
1493  switch ( msg.m_Severity ) {
1494  case eDiag_Info:
1495  case eDiag_Trace:
1496  if ( m_TraceLogRC->IsEnabled() ) {
1497  CMutexGuard lock(s_ApproveMutex);
1498  approved = m_TraceLogRC->Approve();
1499  }
1500  if ( approved ) {
1501  m_TraceLogSuspended = false;
1502  }
1503  else {
1504  *show_warning = !m_TraceLogSuspended.exchange(true);
1505  }
1506  break;
1507  default:
1508  if ( m_ErrLogRC->IsEnabled() ) {
1509  CMutexGuard lock(s_ApproveMutex);
1510  approved = m_ErrLogRC->Approve();
1511  }
1512  if ( approved ) {
1513  m_ErrLogSuspended = false;
1514  }
1515  else {
1516  *show_warning = !m_ErrLogSuspended.exchange(true);
1517  }
1518  }
1519  }
1520  return approved;
1521 }
1522 
1523 
1525 
1527 {
1528  if ( !sm_PID ) {
1530  }
1531  return sm_PID;
1532 }
1533 
1534 
1535 bool CDiagContext::UpdatePID(void)
1536 {
1537  TPID old_pid = sm_PID;
1538  TPID new_pid = CCurrentProcess::GetPid();
1539  if (sm_PID == new_pid) {
1540  return false;
1541  }
1542  sm_PID = new_pid;
1544  TUID old_uid = ctx.GetUID();
1545  // Update GUID to match the new PID
1546  ctx.x_CreateUID();
1547  ctx.Extra().
1548  Print("action", "fork").
1549  Print("parent_guid", ctx.GetStringUID(old_uid)).
1550  Print("parent_pid", NStr::NumericToString(old_pid));
1551  return true;
1552 }
1553 
1554 
1556 {
1557  TPID new_pid = CCurrentProcess::GetPid();
1558  if (sm_PID == new_pid) {
1559  return false;
1560  }
1561  sm_PID = new_pid;
1562  // Update GUID to match the new PID.
1563  // GetDiagContext() call is not async safe in common, but should be safe
1564  // after Diag API initialization, it's just doing a pointer type cast.
1566  return true;
1567 }
1568 
1569 
1570 void CDiagContext::UpdateOnFork(TOnForkFlags flags)
1571 {
1572  if (flags & fOnFork_AsyncSafe) {
1574  return;
1575  }
1576  // not async safe:
1577 
1578  // Do not perform any actions in the parent process
1579  if ( !UpdatePID() ) return;
1580 
1581  if (flags & fOnFork_ResetTimer) {
1582  GetDiagContext().m_StopWatch->Restart();
1583  }
1584  if (flags & fOnFork_PrintStart) {
1586  }
1587 }
1588 
1589 
1592 
1594 {
1595  // This method expected to be async-signal-safe
1596  // https://man7.org/linux/man-pages/man7/signal-safety.7.html
1597  // All non-async-safe code should go to x_CreateUID().
1598 
1599  typedef CDiagContext::TPID TPID;
1600  typedef CDiagContext::TUID TUID;
1601 
1602  TPID pid = CDiagContext::GetPID();
1603  time_t t = time(0);
1604 
1605  base &= 0xFFFF;
1606 
1607  // The low 4 bits are reserved for GUID generator version number.
1608  // As of October 2017 the following versions are used:
1609  // 0 - very old C++ Toolkit
1610  // 1 - contemporary C++ Toolkit
1611  // 2 - ?
1612  // 3 - "C" client (CLOG API); "Python" module 'python-applog'
1613  // 4 - ?
1614  // 5 - Java
1615  // 6 - Scala
1616  // 13 - Perl (NcbiApplog.pm)
1617 
1618  return (TUID(base) << 48) |
1619  ((TUID(pid) & 0xFFFF) << 32) |
1620  ((TUID(t) & 0xFFFFFFF) << 4) |
1621  1; // version #1 - fixed type conversion bug
1622 }
1623 
1625 {
1626  TUID base = kUID_InitBase;
1627  const string& host = GetHost();
1628  for (auto c : host) {
1629  base = base * kUID_Mult + c;
1630  }
1631  m_UID = s_CreateUID(base);
1632 }
1633 
1635 {
1636  // This method expected to be async-signal-safe
1637  // https://man7.org/linux/man-pages/man7/signal-safety.7.html
1638  // Implemented for Unix only, on other platforms works the same
1639  // as a regular x_CreateUID().
1640 
1641 #if defined(NCBI_OS_UNIX)
1642  TUID base = kUID_InitBase;
1643  struct utsname buf;
1644  if (uname(&buf) >= 0) {
1645  const char* s = buf.nodename;
1646  while (*s) {
1647  base = base * kUID_Mult + *s;
1648  s++;
1649  }
1650  }
1651  else {
1652  // Rough workaround in case of uname() error
1653  base = base * kUID_Mult + (TUID)GetPID();
1654  }
1655  m_UID = s_CreateUID(base);
1656 #else
1657  x_CreateUID();
1658 #endif
1659 }
1660 
1661 
1662 DEFINE_STATIC_MUTEX(s_CreateGUIDMutex);
1663 
1665 {
1666  if ( !m_UID ) {
1667  CMutexGuard guard(s_CreateGUIDMutex);
1668  if ( !m_UID ) {
1669  x_CreateUID();
1670  }
1671  }
1672  return m_UID;
1673 }
1674 
1675 
1676 void CDiagContext::GetStringUID(TUID uid, char* buf, size_t buflen) const
1677 {
1678  _ASSERT(buflen > 16);
1679  int hi = int((uid >> 32) & 0xFFFFFFFF);
1680  int lo = int(uid & 0xFFFFFFFF);
1681  snprintf(buf, buflen, "%08X%08X", hi, lo);
1682 }
1683 
1684 
1685 void CDiagContext::GetStringUID(TUID uid, char* buf) const
1686 {
1687  GetStringUID(uid, buf, 17);
1688 }
1689 
1690 
1692 {
1693  char buf[17];
1694  if (uid == 0) {
1695  uid = GetUID();
1696  }
1697  GetStringUID(uid, buf, 17);
1698  return string(buf);
1699 }
1700 
1701 
1703 {
1704  if (uid == 0) {
1705  uid = GetUID();
1706  }
1707  time_t t = time(0);
1708  // Clear old timestamp
1709  uid &= ~((TUID)0xFFFFFFF << 4);
1710  // Add current timestamp
1711  return uid | ((TUID(t) & 0xFFFFFFF) << 4);
1712 }
1713 
1714 
1715 string CDiagContext::GetNextHitID(void) const
1716 {
1717  return x_GetNextHitID(false);
1718 }
1719 
1720 
1721 string CDiagContext::x_GetNextHitID(bool is_default) const
1722 {
1723  static CAtomicCounter s_HitIdCounter;
1724 
1725  Uint8 hi = GetUID();
1726  Uint4 b3 = Uint4((hi >> 32) & 0xFFFFFFFF);
1727  Uint4 b2 = Uint4(hi & 0xFFFFFFFF);
1728 
1730  Uint8 tid = (thr_data.GetTID() & 0xFFFFFF) << 40;
1731  Uint8 rid;
1732  if ( !is_default ) {
1733  rid = ((Uint8)thr_data.GetRequestContext().GetRequestID() & 0xFFFFFF) << 16;
1734  }
1735  else {
1736  rid = ((Uint8)0xFFFFFF) << 16;
1737  }
1738  Uint8 us = (Uint8)(s_HitIdCounter.Add(1) & 0xFFFF);
1739  Uint8 lo = tid | rid | us;
1740  Uint4 b1 = Uint4((lo >> 32) & 0xFFFFFFFF);
1741  Uint4 b0 = Uint4(lo & 0xFFFFFFFF);
1742  char buf[33];
1743  snprintf(buf, 33, "%08X%08X%08X%08X", b3, b2, b1, b0);
1744  return string(buf);
1745 }
1746 
1747 
1749 {
1751 }
1752 
1753 
1754 const string& CDiagContext::GetUsername(void) const
1755 {
1756  return m_Username->GetOriginalString();
1757 }
1758 
1759 
1760 void CDiagContext::SetUsername(const string& username)
1761 {
1762  m_Username->SetString(username);
1763 }
1764 
1765 
1766 const string& CDiagContext::GetHost(void) const
1767 {
1768  // Check context properties
1769  if ( !m_Host->IsEmpty() ) {
1770  return m_Host->GetOriginalString();
1771  }
1772  if ( !m_HostIP.empty() ) {
1773  return m_HostIP;
1774  }
1775 
1776  // All platforms - check NCBI_HOST first.
1777  const TXChar* ncbi_host = NcbiSys_getenv(_TX("NCBI_HOST"));
1778  if (ncbi_host && *ncbi_host) {
1779  m_Host->SetString(_T_STDSTRING(ncbi_host));
1780  return m_Host->GetOriginalString();
1781  }
1782 
1783 #if defined(NCBI_OS_UNIX)
1784  // UNIX - use uname()
1785  {{
1786  struct utsname buf;
1787  if (uname(&buf) >= 0) {
1788  m_Host->SetString(buf.nodename);
1789  return m_Host->GetOriginalString();
1790  }
1791  }}
1792 #endif
1793 
1794 #if defined(NCBI_OS_MSWIN)
1795  // MSWIN - use COMPUTERNAME
1796  const TXChar* compname = NcbiSys_getenv(_TX("COMPUTERNAME"));
1797  if ( compname && *compname ) {
1798  m_Host->SetString(_T_STDSTRING(compname));
1799  return m_Host->GetOriginalString();
1800  }
1801 #endif
1802 
1803  // Server env. - use SERVER_ADDR
1804  const TXChar* servaddr = NcbiSys_getenv(_TX("SERVER_ADDR"));
1805  if ( servaddr && *servaddr ) {
1806  m_Host->SetString(_T_STDSTRING(servaddr));
1807  }
1808  return m_Host->GetOriginalString();
1809 }
1810 
1811 
1812 const string& CDiagContext::GetEncodedHost(void) const
1813 {
1814  if ( !m_Host->IsEmpty() ) {
1815  return m_Host->GetEncodedString();
1816  }
1817  if ( !m_HostIP.empty() ) {
1818  return m_HostIP;
1819  }
1820  // Initialize m_Host, this does not change m_HostIP
1821  GetHost();
1822  return m_Host->GetEncodedString();
1823 }
1824 
1825 
1826 const string& CDiagContext::GetHostname(void) const
1827 {
1828  return m_Host->GetOriginalString();
1829 }
1830 
1831 
1832 const string& CDiagContext::GetEncodedHostname(void) const
1833 {
1834  return m_Host->GetEncodedString();
1835 }
1837 
1838 void CDiagContext::SetHostname(const string& hostname)
1840  m_Host->SetString(hostname);
1844 void CDiagContext::SetHostIP(const string& ip)
1847  m_HostIP.clear();
1848  ERR_POST("Bad host IP value: " << ip);
1849  return;
1850  }
1855 DEFINE_STATIC_MUTEX(s_AppNameMutex);
1856 
1857 const string& CDiagContext::GetAppName(void) const
1858 {
1859  if ( !m_AppNameSet ) {
1860  CMutexGuard guard(s_AppNameMutex);
1861  if ( !m_AppNameSet ) {
1863  // Cache appname if CNcbiApplication instance exists only,
1864  // the Diag API can be used before instance initialization and appname
1865  // could be set to a binary name, and changes later (CXX-5076).
1866  if (CNcbiApplication::Instance() && !m_AppName->IsEmpty()) {
1867  m_AppNameSet = true;
1868  }
1869  }
1870  }
1871  return m_AppName->GetOriginalString();
1872 }
1873 
1874 
1875 const string& CDiagContext::GetEncodedAppName(void) const
1876 {
1877  if ( !m_AppNameSet ) {
1878  GetAppName(); // Initialize app name
1879  }
1880  return m_AppName->GetEncodedString();
1881 }
1882 
1883 
1884 void CDiagContext::SetAppName(const string& app_name)
1885 {
1886  if ( m_AppNameSet ) {
1887  // AppName can be set only once
1888  ERR_POST("Application name cannot be changed.");
1889  return;
1890  }
1891  CMutexGuard guard(s_AppNameMutex);
1892  m_AppName->SetString(app_name);
1893  m_AppNameSet = true;
1894  if ( m_AppName->IsEncoded() ) {
1895  ERR_POST("Illegal characters in application name: '" << app_name <<
1896  "', using URL-encode.");
1897  }
1898 }
1899 
1900 
1902 {
1904 }
1905 
1906 
1908 {
1910 }
1911 
1912 
1914 {
1915  s_AutoWrite_Context->Set(value);
1916 }
1917 
1918 
1919 inline bool IsGlobalProperty(const string& name)
1920 {
1921  return
1928 }
1929 
1930 
1931 void CDiagContext::SetProperty(const string& name,
1932  const string& value,
1934 {
1935  // Global properties
1936  if (name == kProperty_UserName) {
1937  SetUsername(value);
1938  return;
1939  }
1940  if (name == kProperty_HostName) {
1941  SetHostname(value);
1942  return;
1943  }
1944  if (name == kProperty_HostIP) {
1945  SetHostIP(value);
1946  return;
1947  }
1948  if (name == kProperty_AppName) {
1949  SetAppName(value);
1950  return;
1951  }
1952  if (name == kProperty_ExitCode) {
1954  return;
1955  }
1956  if (name == kProperty_ExitSig) {
1958  return;
1959  }
1960 
1961  // Request properties
1962  if (name == kProperty_AppState) {
1963  try {
1965  }
1966  catch (const CException&) {
1967  }
1968  return;
1969  }
1970  if (name == kProperty_ClientIP) {
1972  return;
1973  }
1974  if (name == kProperty_SessionID) {
1976  return;
1977  }
1978  if (name == kProperty_ReqStatus) {
1979  if ( !value.empty() ) {
1982  }
1983  else {
1985  }
1986  return;
1987  }
1988  if (name == kProperty_BytesRd) {
1991  return;
1992  }
1993  if (name == kProperty_BytesWr) {
1996  return;
1997  }
1998  if (name == kProperty_ReqTime) {
1999  // Cannot set this property
2000  return;
2001  }
2002 
2003  if ( mode == eProp_Default ) {
2005  }
2006 
2007  if ( mode == eProp_Global ) {
2009  m_Properties[name] = value;
2010  }
2011  if ( sm_Instance && s_AutoWrite_Context->Get() ) {
2014  }
2015 }
2016 
2017 
2018 string CDiagContext::GetProperty(const string& name,
2019  EPropertyMode mode) const
2020 {
2021  // Global properties
2022  if (name == kProperty_UserName) {
2023  return GetUsername();
2024  }
2025  if (name == kProperty_HostName) {
2026  return GetHostname();
2027  }
2028  if (name == kProperty_HostIP) {
2029  return GetHostIP();
2030  }
2031  if (name == kProperty_AppName) {
2032  return GetAppName();
2033  }
2034  if (name == kProperty_ExitCode) {
2035  return NStr::IntToString(m_ExitCode);
2036  }
2037  if (name == kProperty_ExitSig) {
2038  return NStr::IntToString(m_ExitSig);
2039  }
2040 
2041  // Request properties
2042  if (name == kProperty_AppState) {
2043  return s_AppStateToStr(GetAppState());
2044  }
2045  if (name == kProperty_ClientIP) {
2046  return GetRequestContext().GetClientIP();
2047  }
2048  if (name == kProperty_SessionID) {
2049  return GetSessionID();
2050  }
2051  if (name == kProperty_ReqStatus) {
2053  NStr::IntToString(GetRequestContext().GetRequestStatus())
2054  : kEmptyStr;
2055  }
2056  if (name == kProperty_BytesRd) {
2057  return NStr::Int8ToString(GetRequestContext().GetBytesRd());
2058  }
2059  if (name == kProperty_BytesWr) {
2060  return NStr::Int8ToString(GetRequestContext().GetBytesWr());
2061  }
2062  if (name == kProperty_ReqTime) {
2064  }
2065 
2066  // Check global properties
2069  return gprop != m_Properties.end() ? gprop->second : kEmptyStr;
2070 }
2071 
2072 
2073 void CDiagContext::DeleteProperty(const string& name,
2075 {
2076  // Check global properties
2078  TProperties::iterator gprop = m_Properties.find(name);
2079  if (gprop != m_Properties.end()) {
2080  m_Properties.erase(gprop);
2081  }
2082 }
2083 
2084 
2086 {
2088  ITERATE(TProperties, gprop, m_Properties) {
2090  gprop->first + "=" + gprop->second);
2091  }
2092 }
2093 
2094 
2095 void CDiagContext::PrintStart(const string& message)
2096 {
2098  // Print extra message. If ncbi_role and/or ncbi_location are set,
2099  // they will be logged by this extra. Otherwise nothing will be printed.
2101 
2102  static const char* kCloudIdFile = "/etc/ncbi/cloudid";
2103  CFile cloudid(kCloudIdFile);
2104  if ( cloudid.Exists() ) {
2105  CDiagContext_Extra ex = Extra();
2106  CNcbiIfstream in(kCloudIdFile);
2107  while (!in.eof() && in.good()) {
2108  string s;
2109  getline(in, s);
2110  size_t sep = s.find('\t');
2111  if (sep == NPOS) continue;
2112  string name = NStr::TruncateSpaces(s.substr(0, sep));
2113  string value = s.substr(sep + 1);
2114  ex.Print(name, value);
2115  }
2116  ex.Flush();
2117  }
2118 
2119  x_LogEnvironment();
2120 
2121  // Log NCBI_LOG_FIELDS
2122  map<string, string> env_map;
2123  for (char **env = environ; *env; ++env) {
2124  string n, v;
2126  NStr::ToLower(n);
2127  NStr::ReplaceInPlace(n, "_", "-");
2128  env_map[n] = v;
2129  }
2130 
2131  CNcbiLogFields f("env");
2132  f.LogFields(env_map);
2133 
2134  // Log hit id if already available.
2136 }
2137 
2138 
2140 {
2141  // If no hit id has been logged until app-stop,
2142  // try to force logging now.
2143  if (x_IsSetDefaultHitID()) {
2145  }
2146  else {
2148  if (ctx.IsSetHitID(CRequestContext::eHitID_Request)) {
2149  ctx.x_LogHitID(true);
2150  }
2151  }
2153 }
2154 
2155 
2156 void CDiagContext::PrintExtra(const string& message)
2157 {
2159 }
2160 
2161 
2163 {
2165 }
2166 
2167 
2169  : m_EventType(event_type),
2170  m_Args(0),
2171  m_Counter(new int(1)),
2172  m_Typed(false),
2173  m_PerfStatus(0),
2174  m_PerfTime(0),
2175  m_Flushed(false),
2176  m_AllowBadNames(false)
2177 {
2178 }
2179 
2180 
2182  double timespan,
2183  TExtraArgs& args)
2184  : m_EventType(SDiagMessage::eEvent_PerfLog),
2185  m_Args(0),
2186  m_Counter(new int(1)),
2187  m_Typed(false),
2188  m_PerfStatus(status),
2189  m_PerfTime(timespan),
2190  m_Flushed(false),
2191  m_AllowBadNames(false)
2192 {
2193  if (args.empty()) return;
2194  m_Args = new TExtraArgs;
2195  m_Args->splice(m_Args->end(), args);
2196 }
2197 
2198 
2200  : m_EventType(const_cast<CDiagContext_Extra&>(args).m_EventType),
2201  m_Args(const_cast<CDiagContext_Extra&>(args).m_Args),
2202  m_Counter(const_cast<CDiagContext_Extra&>(args).m_Counter),
2203  m_Typed(args.m_Typed),
2204  m_PerfStatus(args.m_PerfStatus),
2205  m_PerfTime(args.m_PerfTime),
2206  m_Flushed(args.m_Flushed),
2207  m_AllowBadNames(args.m_AllowBadNames)
2208 {
2209  (*m_Counter)++;
2210 }
2211 
2212 
2214 {
2215  m_AllowBadNames = true;
2216  return *this;
2217 }
2218 
2219 
2222 
2223 
2225 {
2226  const string& role = CDiagContext::GetHostRole();
2227  const string& loc = CDiagContext::GetHostLocation();
2228  if ( !role.empty() ) {
2229  Print("ncbi_role", role);
2230  }
2231  if ( !loc.empty() ) {
2232  Print("ncbi_location", loc);
2233  }
2234  return *this;
2235 }
2236 
2238 {
2239  Print("ncbi_app_username", CSystemInfo::GetUserName());
2241  if (ins) {
2242  Print("ncbi_app_path", ins->GetProgramExecutablePath());
2243  const CVersionAPI& ver = ins->GetFullVersion();
2244  if (!ver.GetBuildInfo().date.empty()) {
2245  Print("ncbi_app_build_date", ver.GetBuildInfo().date);
2246  }
2247 #if NCBI_PACKAGE
2248  Print("ncbi_app_package_name", ver.GetPackageName());
2249  string pkv = NStr::NumericToString(ver.GetPackageVersion().GetMajor())
2252  Print("ncbi_app_package_version", pkv);
2253  Print("ncbi_app_package_date", NCBI_SBUILDINFO_DEFAULT().date);
2254 #endif
2255  const SBuildInfo& bi = ver.GetBuildInfo();
2256  initializer_list<SBuildInfo::EExtra> bi_num = {
2262  };
2263  for(SBuildInfo::EExtra key : bi_num) {
2264  string value = bi.GetExtraValue(key);
2265  if (!value.empty()) {
2267  }
2268  }
2269  return *this;
2270  }
2271 #if defined(NCBI_TEAMCITY_PROJECT_NAME)
2272  Print("ncbi_app_tc_project", NCBI_TEAMCITY_PROJECT_NAME);
2273 #endif
2274 #if defined(NCBI_TEAMCITY_BUILDCONF_NAME)
2275  Print("ncbi_app_tc_conf", NCBI_TEAMCITY_BUILDCONF_NAME);
2276 #endif
2277 #if defined(NCBI_TEAMCITY_BUILD_NUMBER)
2278  Print("ncbi_app_tc_build", NStr::NumericToString<Uint8>(NCBI_TEAMCITY_BUILD_NUMBER));
2279 #endif
2280 #if defined(NCBI_TEAMCITY_BUILD_ID)
2281  Print("ncbi_app_build_id", NCBI_TEAMCITY_BUILD_ID);
2282 #endif
2283 
2284  return *this;
2285 }
2286 
2288 {
2290  if (ins) {
2291  const CVersionAPI& ver = ins->GetFullVersion();
2292  const CVersionInfo& vi = ver.GetVersionInfo();
2293 //#if defined (NCBI_SC_VERSION) && NCBI_SC_VERSION <= 21
2294 #if 1
2295  string str = NStr::NumericToString(vi.GetMajor()) + "." +
2296  NStr::NumericToString(vi.GetMinor()) + "." +
2298  Print("ncbi_app_version", str);
2299 #else
2300  initializer_list<int> vi_num = {vi.GetMajor(), vi.GetMinor(), vi.GetPatchLevel()};
2301  Print("ncbi_app_version", NStr::JoinNumeric(vi_num.begin(), vi_num.end(), "."));
2302 #endif
2303 
2304  const SBuildInfo& bi = ver.GetBuildInfo();
2305  initializer_list<SBuildInfo::EExtra> bi_num =
2309  for(SBuildInfo::EExtra key : bi_num) {
2310  string value = bi.GetExtraValue(key);
2311  if (!value.empty()) {
2313  }
2314  }
2315  return *this;
2316  }
2317 #if defined(NCBI_PRODUCTION_VER)
2318  Print("ncbi_app_prod_version", NStr::NumericToString<Uint8>(NCBI_PRODUCTION_VER));
2319 #elif defined(NCBI_DEVELOPMENT_VER)
2320  Print("ncbi_app_dev_version", NStr::NumericToString<Uint8>(NCBI_DEVELOPMENT_VER));
2321 #endif
2322 #if defined(NCBI_SC_VERSION)
2323  Print("ncbi_app_sc_version", NStr::NumericToString<Uint8>(NCBI_SC_VERSION));
2324 #endif
2325 #if defined(NCBI_SUBVERSION_REVISION)
2326  Print("ncbi_app_vcs_revision", NStr::NumericToString<Uint8>(NCBI_SUBVERSION_REVISION));
2327 #endif
2328  return *this;
2329 }
2330 
2331 
2333 {
2335  return;
2336  }
2337 
2338  // Add ncbi-role and ncbi-location just before setting m_Flushed flag.
2341  }
2342  // Prevent double-flush
2343  m_Flushed = true;
2344 
2345  // Ignore extra messages without arguments. Allow request-start/request-stop
2346  // and stop without arguments. Empty start messages are printed only if
2347  // ncbi_role/ncbi_location are available (see above).
2350  (!m_Args || m_Args->empty()) ) {
2351  return;
2352  }
2353 
2355  EDiagAppState app_state = ctx.GetAppState();
2356  bool app_state_updated = false;
2358  if (app_state != eDiagAppState_RequestBegin &&
2359  app_state != eDiagAppState_Request) {
2360  ctx.SetAppState(eDiagAppState_RequestBegin);
2361  app_state_updated = true;
2362  }
2364  }
2366  if (app_state != eDiagAppState_RequestEnd) {
2367  ctx.SetAppState(eDiagAppState_RequestEnd);
2368  app_state_updated = true;
2369  }
2370  }
2371 
2372  string s;
2374  s.append(to_string(m_PerfStatus)).append(1, ' ')
2376  }
2377 
2378  if (!s_DisableAppLog->Get()) {
2379  SDiagMessage mess(eDiag_Info,
2380  s.data(), s.size(),
2381  0, 0, // file, line
2383  NULL,
2384  0, 0, // err code/subcode
2385  NULL,
2386  0, 0, 0); // module/class/function
2387  mess.m_Event = m_EventType;
2388  if (m_Args && !m_Args->empty()) {
2389  mess.m_ExtraArgs.splice(mess.m_ExtraArgs.end(), *m_Args);
2390  }
2391  mess.m_TypedExtra = m_Typed;
2393 
2394  GetDiagBuffer().DiagHandler(mess);
2395  }
2396 
2397  if ( app_state_updated ) {
2399  ctx.SetAppState(eDiagAppState_Request);
2400  }
2402  ctx.SetAppState(eDiagAppState_AppRun);
2403  }
2404  }
2405 }
2406 
2407 
2409 {
2410  if ( m_Counter && --(*m_Counter) == 0) {
2411  Flush();
2412  delete m_Args;
2413  m_Args = 0;
2414  }
2415 }
2416 
2417 
2420 {
2421  if (this != &args) {
2422  x_Release();
2423  m_Args = const_cast<CDiagContext_Extra&>(args).m_Args;
2424  m_Counter = const_cast<CDiagContext_Extra&>(args).m_Counter;
2425  m_Typed = args.m_Typed;
2426  m_PerfStatus = args.m_PerfStatus;
2427  m_PerfTime = args.m_PerfTime;
2428  m_Flushed = args.m_Flushed;
2430  (*m_Counter)++;
2431  }
2432  return *this;
2433 }
2434 
2435 
2437 {
2438  x_Release();
2439  if ( *m_Counter == 0) {
2440  delete m_Counter;
2441  }
2442 }
2443 
2445 {
2446  // Only allow extra events to be printed/flushed multiple times
2448  ERR_POST_ONCE(
2449  "Attempt to set request start/stop arguments after flushing");
2450  return false;
2451  }
2452 
2453  // For extra messages reset flushed state.
2454  m_Flushed = false;
2455  return true;
2456 }
2457 
2458 
2459 static const char* kNcbiApplogKeywordStrings[] = {
2460  // ncbi_phid, self_url and http_referrer are reported by corelib and cgi
2461  // and should not be renamed.
2462  /*
2463  "ncbi_phid",
2464  "self_url",
2465  "http_referrer",
2466  "prev_phid",
2467  */
2468  "app",
2469  "host",
2470  "ip",
2471  "ip_addr",
2472  "session_id",
2473  "date",
2474  "datetime",
2475  "time",
2476  "guid",
2477  "acc_time_secs",
2478  "bytes_in_bit",
2479  "bytes_out_bit",
2480  "day",
2481  "day_of_week",
2482  "day_of_year",
2483  "exec_time_msec_bit",
2484  "start_time_msec",
2485  "second",
2486  "minute",
2487  "hour",
2488  "iter",
2489  "month",
2490  "pid",
2491  "status",
2492  "tid",
2493  "year",
2494  "geo_metro_code",
2495  "geo_latitude_hundredths",
2496  "geo_longitude_hundredths",
2497  "session_pageviews",
2498  "ping_count",
2499  "session_duration",
2500  "visit_duration",
2501  "time_on_page",
2502  "time_to_last_ping",
2503  "bytes_in",
2504  "bytes_out",
2505  "exec_time_msec",
2506  "self_url_path",
2507  "self_url_host",
2508  "self_url_file",
2509  "self_url_file_ext",
2510  "self_url_top_level_dir",
2511  "self_url_directory",
2512  "referrer",
2513  "ref_url",
2514  "ref_host",
2515  "http_referer",
2516  "referer",
2517  "interactive_hit",
2518  "statusuidlookup",
2519  "usageuidlookup",
2520  "all",
2521  "has_app_data",
2522  "has_critical",
2523  "has_duplicate_nexus",
2524  "has_duplicate_phid",
2525  "has_error",
2526  "has_fatal",
2527  "has_info",
2528  "has_multiple_phid",
2529  "has_ping",
2530  "has_start",
2531  "has_stop",
2532  "has_warning",
2533  "is_app_hit",
2534  "is_perf",
2535  "multiple_session_hit",
2536  "multiple_session_ip",
2537  "ncbi_phid_first_render",
2538  "phid_from_other_request",
2539  "phid_stack_ambiguous_relationship",
2540  "phid_stack_has_fake_child",
2541  "phid_stack_has_fake_parent",
2542  "phid_stack_missing_child",
2543  "phid_stack_missing_parent",
2544  "phid_stack_multivalued",
2545  "session_bot",
2546  "session_bot_by_ip",
2547  "session_bot_by_rate",
2548  "session_bot_by_user_agent",
2549  "session_bot_ip",
2550  "session_has_ping",
2551  "browser_name",
2552  "browser_version",
2553  "browser_major_version",
2554  "browser_platform",
2555  "browser_engine",
2556  "is_mobile",
2557  "is_tablet",
2558  "is_phone",
2559  "is_browser_bot",
2560  "applog_db_path",
2561  "applog_db_size",
2562  "applog_db_size_hit_fraction",
2563  "applog_db_machine",
2564  "applog_db_vol_id",
2565  "applog_db_type",
2566  "applog_db_date_tag",
2567  "applog_db_date_range",
2568  "applog_db_stream",
2569  "applog_db_create_time",
2570  "applog_db_modify_time",
2571  "applog_db_state",
2572  "applog_db_uid",
2573  "applog_db_agent_host",
2574  "applog_db_agent_pid",
2575  "applog_db_agent_tid",
2576  "applog_db_volume_served_time",
2577  "phid_stack_missing_parent",
2578  "phid_stack_missing_child",
2579  "phid_stack_has_fake_child",
2580  "phid_stack_has_fake_parent",
2581  "phid_stack_ambiguous_relationship",
2582  "phid_stack_multivalued",
2583  "ncbi_phid_first_render",
2584  "multiple_session_hit",
2585  "has_ping",
2586  "session_has_ping",
2587  "has_duplicate_nexus",
2588  "has_app_data",
2589  "has_multiple_phid",
2590  "multi_hit_phid",
2591  "session_bot_by_rate",
2592  "session_bot_by_user_agent",
2593  "session_bot",
2594  "session_bot_by_ip",
2595  "session_bot_ip",
2596  "multiple_session_ip",
2597  "collapsed_jsevent"
2598 };
2599 
2600 
2602 {
2603  typedef unordered_set<string> TKeywords;
2604 
2606  {
2607  TKeywords* kw = new TKeywords;
2608  int sz = sizeof(kNcbiApplogKeywordStrings) / sizeof(kNcbiApplogKeywordStrings[0]);
2609  for (int i = 0; i < sz; ++i) {
2610  kw->insert(kNcbiApplogKeywordStrings[i]);
2611  }
2612  return kw;
2613  }
2614 
2615  void Cleanup(TKeywords& /*keywords*/) {}
2616 };
2617 
2618 
2620 
2622 CDiagContext_Extra::Print(const string& name, const string& value)
2623 {
2624  if ( !x_CanPrint() ) {
2625  return *this;
2626  }
2627 
2628  if ( !m_Args ) {
2629  m_Args = new TExtraArgs;
2630  }
2631 
2632  // Optimize inserting new pair into the args list, it is the same as:
2633  // m_Args->push_back(TExtraArg(name, value));
2634  m_Args->push_back(TExtraArg(kEmptyStr, kEmptyStr));
2635 
2636  // If arg name is a reserved applog keywork, rename it and log warning.
2638  if (kw.find(name) == kw.end()) {
2639  m_Args->rbegin()->first.assign(name);
2640  }
2641  else {
2642  string renamed = "auto_renamed_applog_keyword__" + name;
2643  m_Args->rbegin()->first.assign(renamed);
2644  ERR_POST("'" << name
2645  << "' is a reserved NCBI AppLog keyword, so it has been renamed to "
2646  << renamed);
2647  }
2648  m_Args->rbegin()->second.assign(value);
2649  return *this;
2650 }
2651 
2653 CDiagContext_Extra::Print(const string& name, const char* value)
2654 {
2655  return Print(name, string(value));
2656 }
2657 
2659 CDiagContext_Extra::Print(const string& name, int value)
2660 {
2661  return Print(name, NStr::IntToString(value));
2662 }
2663 
2665 CDiagContext_Extra::Print(const string& name, unsigned int value)
2666 {
2667  return Print(name, NStr::UIntToString(value));
2668 }
2669 
2671 CDiagContext_Extra::Print(const string& name, long value)
2672 {
2673  return Print(name, NStr::LongToString(value));
2674 }
2675 
2677 CDiagContext_Extra::Print(const string& name, unsigned long value)
2678 {
2679  return Print(name, NStr::ULongToString(value));
2680 }
2681 
2682 #if !NCBI_INT8_IS_LONG
2685 {
2686  return Print(name, NStr::Int8ToString(value));
2687 }
2690 {
2691  return Print(name, NStr::UInt8ToString(value));
2692 }
2693 #elif SIZEOF_LONG_LONG
2695 CDiagContext_Extra::Print(const string& name, long long value)
2696 {
2697  return Print(name, NStr::Int8ToString(value));
2698 }
2699 
2701 CDiagContext_Extra::Print(const string& name, unsigned long long value)
2702 {
2703  return Print(name, NStr::UInt8ToString(value));
2704 }
2705 #endif
2706 
2708 CDiagContext_Extra::Print(const string& name, char value)
2709 {
2710  return Print(name, string(1,value));
2711 }
2712 
2714 CDiagContext_Extra::Print(const string& name, signed char value)
2715 {
2716  return Print(name, string(1,value));
2717 }
2718 
2720 CDiagContext_Extra::Print(const string& name, unsigned char value)
2721 {
2722  return Print(name, string(1,value));
2723 }
2724 
2726 CDiagContext_Extra::Print(const string& name, double value)
2727 {
2728  return Print(name, NStr::DoubleToString(value));
2729 }
2730 
2732 CDiagContext_Extra::Print(const string& name, bool value)
2733 {
2734  return Print(name, NStr::BoolToString(value));
2735 }
2736 
2739 {
2740  if ( !x_CanPrint() ) {
2741  return *this;
2742  }
2743 
2744  if ( !m_Args ) {
2745  m_Args = new TExtraArgs;
2746  }
2747  m_Args->splice(m_Args->end(), args);
2748  return *this;
2749 }
2750 
2751 
2752 static const char* kExtraTypeArgName = "NCBIEXTRATYPE";
2753 
2755 {
2756  m_Typed = true;
2758  return *this;
2759 }
2760 
2761 
2762 void CDiagContext::PrintRequestStart(const string& message)
2763 {
2764  EDiagAppState app_state = GetAppState();
2765  bool app_state_updated = false;
2766  if (app_state != eDiagAppState_RequestBegin &&
2767  app_state != eDiagAppState_Request) {
2769  app_state_updated = true;
2770  }
2772  if ( app_state_updated ) {
2774  }
2775 }
2776 
2777 
2779 {
2780  EDiagAppState app_state = GetAppState();
2781  bool app_state_updated = false;
2782  if (app_state != eDiagAppState_RequestEnd) {
2784  app_state_updated = true;
2785  }
2787  if ( app_state_updated ) {
2789  // Now back at application level check if a default hit id
2790  // needs to be logged.
2792  }
2793 }
2794 
2795 
2797 {
2798  return m_AppState;
2799 }
2800 
2801 
2803 {
2804  // This checks thread's state first, then calls GetAppState if necessary.
2805  return GetRequestContext().GetAppState();
2806 }
2807 
2808 
2810 {
2811  m_AppState = state;
2812 }
2813 
2814 
2816 {
2818  switch ( state ) {
2820  case eDiagAppState_AppRun:
2821  case eDiagAppState_AppEnd:
2822  {
2823  ctx.SetAppState(eDiagAppState_NotSet);
2824  m_AppState = state;
2825  break;
2826  }
2828  case eDiagAppState_Request:
2830  ctx.SetAppState(state);
2831  break;
2832  default:
2833  ERR_POST_X(17, Warning << "Invalid EDiagAppState value");
2834  }
2835 }
2836 
2837 
2839 {
2840  switch ( mode ) {
2841  case eProp_Default:
2842  SetAppState(state);
2843  break;
2844  case eProp_Global:
2846  break;
2847  case eProp_Thread:
2849  break;
2850  }
2851 }
2852 
2853 
2854 // Session id passed through HTTP
2855 NCBI_PARAM_DECL(string, Log, Http_Session_Id);
2856 NCBI_PARAM_DEF_EX(string, Log, Http_Session_Id, "", eParam_NoThread,
2857  HTTP_NCBI_SID);
2858 static CSafeStatic<NCBI_PARAM_TYPE(Log, Http_Session_Id)> s_HttpSessionId;
2859 
2860 // Session id set in the environment
2861 NCBI_PARAM_DECL(string, Log, Session_Id);
2862 NCBI_PARAM_DEF_EX(string, Log, Session_Id, "", eParam_NoThread,
2863  NCBI_LOG_SESSION_ID);
2865 
2866 
2867 DEFINE_STATIC_MUTEX(s_DefaultSidMutex);
2868 
2869 string CDiagContext::GetDefaultSessionID(void) const
2870 {
2871  CMutexGuard lock(s_DefaultSidMutex);
2872  if (m_DefaultSessionId.get() && !m_DefaultSessionId->IsEmpty()) {
2873  return m_DefaultSessionId->GetOriginalString();
2874  }
2875 
2876  // Needs initialization.
2877  if ( !m_DefaultSessionId.get() ) {
2879  }
2880  if ( m_DefaultSessionId->IsEmpty() ) {
2882  s_HttpSessionId->Get());
2883  if ( sid.empty() ) {
2885  s_DefaultSessionId->Get());
2886  }
2887  m_DefaultSessionId->SetString(sid);
2888  }
2889  return m_DefaultSessionId->GetOriginalString();
2890 }
2891 
2892 
2893 void CDiagContext::SetDefaultSessionID(const string& session_id)
2894 {
2895  CMutexGuard lock(s_DefaultSidMutex);
2896  if ( !m_DefaultSessionId.get() ) {
2898  }
2899  m_DefaultSessionId->SetString(session_id);
2900 }
2901 
2902 
2903 string CDiagContext::GetSessionID(void) const
2904 {
2906  if ( rctx.IsSetExplicitSessionID() ) {
2907  return rctx.GetSessionID();
2908  }
2909  return GetDefaultSessionID();
2910 }
2911 
2912 
2913 string CDiagContext::GetEncodedSessionID(void) const
2914 {
2916  if ( rctx.IsSetExplicitSessionID() ) {
2917  return rctx.GetEncodedSessionID();
2918  }
2919  GetDefaultSessionID(); // Make sure the default value is initialized.
2920  CMutexGuard lock(s_DefaultSidMutex);
2921  _ASSERT(m_DefaultSessionId.get());
2922  return m_DefaultSessionId->GetEncodedString();
2923 }
2924 
2925 
2926 NCBI_PARAM_DECL(string, Log, Client_Ip);
2927 NCBI_PARAM_DEF_EX(string, Log, Client_Ip, "", eParam_NoThread,
2928  NCBI_LOG_CLIENT_IP);
2930 
2931 
2933 {
2934  return s_DefaultClientIp->Get();
2935 }
2936 
2937 
2938 void CDiagContext::SetDefaultClientIP(const string& client_ip)
2939 {
2940  s_DefaultClientIp->Set(client_ip);
2941 }
2942 
2943 
2944 // Hit id passed through HTTP
2945 NCBI_PARAM_DECL(string, Log, Http_Hit_Id);
2946 NCBI_PARAM_DEF_EX(string, Log, Http_Hit_Id, "", eParam_NoThread,
2947  HTTP_NCBI_PHID);
2948 static CSafeStatic<NCBI_PARAM_TYPE(Log, Http_Hit_Id)> s_HttpHitId;
2949 
2950 // Hit id set in the environment or registry
2951 NCBI_PARAM_DECL(string, Log, Hit_Id);
2952 NCBI_PARAM_DEF_EX(string, Log, Hit_Id, "", eParam_NoThread,
2953  NCBI_LOG_HIT_ID);
2954 static CSafeStatic<NCBI_PARAM_TYPE(Log, Hit_Id)> s_HitId;
2955 
2956 
2957 DEFINE_STATIC_MUTEX(s_DefaultHidMutex);
2958 
2960 {
2962  return (state == eDiagAppState_AppBegin) ||
2963  (state == eDiagAppState_AppRun) ||
2965 }
2966 
2967 
2969 {
2970  // NOTE: The method must be always called with s_DefaultHidMutex locked.
2971 
2972  // Log the default hit id only when at application level. Otherwise
2973  // pospone it untill request-stop/app-stop.
2974  if (m_LoggedHitId || !m_DefaultHitId.get() || m_DefaultHitId->Empty() ||
2976  return;
2977  }
2979  m_LoggedHitId = true;
2980 }
2981 
2982 
2984 {
2985  CMutexGuard guard(s_DefaultHidMutex);
2986  x_LogHitID();
2987 }
2988 
2989 
2991 {
2992  CMutexGuard guard(s_DefaultHidMutex);
2993  return m_DefaultHitId.get() && !m_DefaultHitId->Empty();
2994 }
2995 
2996 
2998 {
2999  CMutexGuard guard(s_DefaultHidMutex);
3000  if (m_DefaultHitId.get() && !m_DefaultHitId->Empty()) {
3001  return *m_DefaultHitId;
3002  }
3003 
3004  if ( !m_DefaultHitId.get() ) {
3005  m_DefaultHitId.reset(new CSharedHitId());
3006  }
3007  if ( m_DefaultHitId->Empty() ) {
3009  s_HttpHitId->Get()));
3010  if ( m_DefaultHitId->Empty() ) {
3011  string phid = CRequestContext::SelectLastHitID(
3012  s_HitId->Get());
3013  if ( !phid.empty() ) {
3014  const char* c_env_job_id = getenv("JOB_ID");
3015  string env_job_id = c_env_job_id ? string(c_env_job_id): "";
3016  const char* c_env_task_id = getenv("SGE_TASK_ID");
3017  string env_task_id = c_env_task_id ? string(c_env_task_id) : "";
3018  if (env_task_id.find_first_not_of("0123456789") != NPOS) {
3019  // If task id is 'undefined', set it to 1 - it's a job with
3020  // just one task.
3021  env_task_id = "1";
3022  }
3023  if (!env_job_id.empty() && !env_task_id.empty()) {
3024  // FIX LATER: It's better to use J and T prefix
3025  // to indicate job/task, but currently CRequestContext
3026  // logs errors if sub-hit id contains non-digits.
3027  // Using leading 0s is a temporary solution. Later,
3028  // when most apps are recompiled with the new
3029  // CRequestContext, we can reconsider using J/T.
3030  string jid = ".000" + env_job_id;
3031  string tid = ".00" + env_task_id;
3032  size_t jid_pos = phid.find(jid);
3033  if (jid_pos == NPOS) {
3034  // No current job id in the phid.
3035  phid += jid + tid;
3036  }
3037  else {
3038  // Job id is already in the phid. Check task id.
3039  if (phid.find(tid, jid_pos + jid.size()) == NPOS) {
3040  // New task in the same job.
3041  phid += tid;
3042  }
3043  // else - task id already in the phid. Ignore.
3044  }
3045  }
3046  }
3047  m_DefaultHitId->SetHitId(phid);
3048  }
3049  if (m_DefaultHitId->Empty() && (flag == eHitID_Create)) {
3050  m_DefaultHitId->SetHitId(x_GetNextHitID(true));
3051  }
3052  }
3053  // Default hit id always uses shared sub-hit counter.
3054  m_DefaultHitId->SetShared();
3056  // Log hit id if at application level.
3057  x_LogHitID();
3058  return *m_DefaultHitId;
3059 }
3060 
3061 
3062 void CDiagContext::SetDefaultHitID(const string& hit_id)
3063 {
3064  CMutexGuard guard(s_DefaultHidMutex);
3065  if ( !m_DefaultHitId.get() ) {
3066  m_DefaultHitId.reset(new CSharedHitId());
3067  }
3068  m_DefaultHitId->SetHitId(hit_id);
3069  // Default hit id always uses shared sub-hit counter.
3070  m_DefaultHitId->SetShared();
3071  // Log new hit id when at application level.
3072  m_LoggedHitId = false;
3073  x_LogHitID();
3074 }
3075 
3076 
3077 inline string s_ReadString(const char* filename)
3078 {
3079  string ret;
3080  CNcbiIfstream in(filename);
3081  if ( in.good() ) {
3082  getline(in, ret);
3083  }
3084  return ret;
3085 }
3086 
3087 
3090 
3091 const string& CDiagContext::GetHostRole(void)
3092 {
3093  if ( !s_HostRole->get() ) {
3095  if ( !s_HostRole->get() ) {
3096  unique_ptr<string> role(new string);
3097  const TXChar* env_role = NcbiSys_getenv(_TX("NCBI_ROLE"));
3098  if (env_role && *env_role) {
3099  *role = string(_T_CSTRING(env_role));
3100  }
3101  else {
3102  *role = s_ReadString("/etc/ncbi/role");
3103  }
3104  s_HostRole->reset(role.release());
3105  }
3106  }
3107  return **s_HostRole;
3108 }
3109 
3110 
3112 {
3113  if ( !s_HostLocation->get() ) {
3115  if ( !s_HostLocation->get() ) {
3116  unique_ptr<string> loc(new string);
3117  const TXChar* env_loc = NcbiSys_getenv(_TX("NCBI_LOCATION"));
3118  if (env_loc && *env_loc) {
3119  *loc = string(_T_CSTRING(env_loc));
3120  }
3121  else {
3122  *loc = s_ReadString("/etc/ncbi/location");
3123  }
3124  s_HostLocation->reset(loc.release());
3125  }
3126  }
3127  return **s_HostLocation;
3128 }
3129 
3130 
3131 const char* CDiagContext::kProperty_UserName = "user";
3132 const char* CDiagContext::kProperty_HostName = "host";
3133 const char* CDiagContext::kProperty_HostIP = "host_ip_addr";
3134 const char* CDiagContext::kProperty_ClientIP = "client_ip";
3135 const char* CDiagContext::kProperty_SessionID = "session_id";
3136 const char* CDiagContext::kProperty_AppName = "app_name";
3137 const char* CDiagContext::kProperty_AppState = "app_state";
3138 const char* CDiagContext::kProperty_ExitSig = "exit_signal";
3139 const char* CDiagContext::kProperty_ExitCode = "exit_code";
3140 const char* CDiagContext::kProperty_ReqStatus = "request_status";
3141 const char* CDiagContext::kProperty_ReqTime = "request_time";
3142 const char* CDiagContext::kProperty_BytesRd = "bytes_rd";
3143 const char* CDiagContext::kProperty_BytesWr = "bytes_wr";
3144 
3145 static const char* kDiagTimeFormat = "Y-M-DTh:m:s.rZ";
3146 // Fixed fields' widths
3147 static const int kDiagW_PID = 5;
3148 static const int kDiagW_TID = 3;
3149 static const int kDiagW_RID = 4;
3150 static const int kDiagW_AppState = 2;
3151 static const int kDiagW_SN = 4;
3152 static const int kDiagW_UID = 16;
3153 static const int kDiagW_Host = 15;
3154 static const int kDiagW_Client = 15;
3155 static const int kDiagW_Session = 24;
3156 
3157 static const char* kUnknown_Host = "UNK_HOST";
3158 static const char* kUnknown_Client = "UNK_CLIENT";
3159 static const char* kUnknown_Session = "UNK_SESSION";
3160 static const char* kUnknown_App = "UNK_APP";
3161 
3162 
3164  const SDiagMessage& msg) const
3165 {
3166  char uid[17];
3167  GetStringUID(msg.GetUID(), uid, 17);
3168  const string& host = msg.GetHost();
3169  string client = msg.GetClient();
3170  string session = msg.GetSession();
3171  const string& app = msg.GetAppName();
3172  const char* app_state = s_AppStateToStr(msg.GetAppState());
3173 
3174  // Print common fields
3175  ostr << setfill('0') << setw(kDiagW_PID) << msg.m_PID << '/'
3176  << setw(kDiagW_TID) << msg.m_TID << '/'
3177  << setw(kDiagW_RID) << msg.m_RequestId
3178  << "/"
3179  << setfill(' ') << setw(kDiagW_AppState) << setiosflags(IOS_BASE::left)
3180  << app_state << resetiosflags(IOS_BASE::left)
3181  << ' ' << setw(0) << setfill(' ') << uid << ' '
3182  << setfill('0') << setw(kDiagW_SN) << msg.m_ProcPost << '/'
3183  << setw(kDiagW_SN) << msg.m_ThrPost << ' '
3184  << setw(0) << msg.GetTime().AsString(kDiagTimeFormat) << ' '
3185  << setfill(' ') << setiosflags(IOS_BASE::left)
3186  << setw(kDiagW_Host)
3187  << (host.empty() ? kUnknown_Host : host.c_str()) << ' '
3188  << setw(kDiagW_Client)
3189  << (client.empty() ? kUnknown_Client : client.c_str()) << ' '
3190  << setw(kDiagW_Session)
3191  << (session.empty() ? kUnknown_Session : session.c_str()) << ' '
3192  << resetiosflags(IOS_BASE::left) << setw(0)
3193  << (app.empty() ? kUnknown_App : app.c_str()) << ' ';
3194 }
3195 
3196 
3198 {
3199  // Reset properties
3201  if ( ctx.IsRunning() ) {
3202  // The request is already running -
3203  // duplicate request start or missing request stop
3204  ERR_POST_ONCE(
3205  "Duplicate request-start or missing request-stop");
3206  }
3207 
3208  // Use the default client ip if no other value is set.
3209  if ( !ctx.IsSetExplicitClientIP() ) {
3210  string ip = GetDefaultClientIP();
3211  if ( !ip.empty() ) {
3212  ctx.SetClientIP(ip);
3213  }
3214  }
3215 
3216  ctx.StartRequest();
3217  x_LogEnvironment();
3218 }
3219 
3220 
3222 {
3223  // Print selected environment and registry values.
3224  static CSafeStatic<NCBI_PARAM_TYPE(Log, LogEnvironment)> s_LogEnvironment;
3225  string log_args = s_LogEnvironment->Get();
3226  if ( !log_args.empty() ) {
3227  list<string> log_args_list;
3228  NStr::Split(log_args, " ", log_args_list,
3231  extra.Print("LogEnvironment", "true");
3232  {{
3233  // The guard must be released before flushing the extra -
3234  // otherwise there may be a deadlock when accessing CParam-s
3235  // from other threads.
3237  if ( app ) {
3238  const CNcbiEnvironment& env = app->GetEnvironment();
3239  ITERATE(list<string>, it, log_args_list) {
3240  const string& val = env.Get(*it);
3241  extra.Print(*it, val);
3242  }
3243  }
3244  }}
3245  extra.Flush();
3246  }
3247  static CSafeStatic<NCBI_PARAM_TYPE(Log, LogRegistry)> s_LogRegistry;
3248  log_args = s_LogRegistry->Get();
3249  if ( !log_args.empty() ) {
3250  list<string> log_args_list;
3251  NStr::Split(log_args, " ", log_args_list,
3254  extra.Print("LogRegistry", "true");
3255  {{
3256  // The guard must be released before flushing the extra -
3257  // see above.
3259  if ( app ) {
3260  const CNcbiRegistry& reg = app->GetConfig();
3261  ITERATE(list<string>, it, log_args_list) {
3262  string section, name;
3263  NStr::SplitInTwo(*it, ":", section, name);
3264  const string& val = reg.Get(section, name);
3265  extra.Print(*it, val);
3266  }
3267  }
3268  }}
3269  extra.Flush();
3270  }
3271 }
3272 
3273 
3275  const string& message)
3276 {
3277  if ( IsSetOldPostFormat() ) {
3278  return;
3279  }
3280  string str;
3281  string prop;
3282  bool need_space = false;
3284 
3285  switch ( event ) {
3288  break;
3290  {
3291  x_StartRequest();
3292  break;
3293  }
3295  str.append(to_string(GetExitCode())).append(1, ' ').append(m_StopWatch->AsString());
3296  if (GetExitSignal() != 0) {
3297  str.append(" SIG=").append(to_string(GetExitSignal()));
3298  }
3299  need_space = true;
3300  break;
3302  {
3303  if ( !ctx.IsRunning() ) {
3304  // The request is not running -
3305  // duplicate request stop or missing request start
3306  ERR_POST_ONCE(
3307  "Duplicate request-stop or missing request-start");
3308  }
3309  str.append(to_string(ctx.GetRequestStatus())).append(1, ' ')
3310  .append(ctx.GetRequestTimer().AsString()).append(1, ' ')
3311  .append(to_string(ctx.GetBytesRd())).append(1, ' ')
3312  .append(to_string(ctx.GetBytesWr()));
3313  need_space = true;
3314  break;
3315  }
3316  default:
3317  return; // Prevent warning about other event types.
3318  }
3319  if ( !message.empty() ) {
3320  if (need_space) {
3321  str.append(1, ' ');
3322  }
3323  str.append(message);
3324  }
3325 
3326  if (!s_DisableAppLog->Get()) {
3327  SDiagMessage mess(eDiag_Info,
3328  str.data(), str.size(),
3329  0, 0, // file, line
3331  NULL,
3332  0, 0, // err code/subcode
3333  NULL,
3334  0, 0, 0); // module/class/function
3335  mess.m_Event = event;
3336  CDiagBuffer::DiagHandler(mess);
3337  }
3338 
3339  if (event == SDiagMessage::eEvent_RequestStop) {
3340  // Reset request context after stopping the request.
3341  ctx.StopRequest();
3342  }
3343 }
3344 
3345 
3347 {
3348  return s_OldPostFormat->Get();
3349 }
3350 
3351 
3353 {
3354  s_OldPostFormat->Set(value);
3355 }
3356 
3357 
3359 {
3360  return s_PrintSystemTID->Get();
3361 }
3362 
3363 
3365 {
3366  s_PrintSystemTID->Set(value);
3367 }
3368 
3369 
3370 void CDiagContext::InitMessages(size_t max_size)
3371 {
3372  if ( !m_Messages.get() ) {
3373  m_Messages.reset(new TMessages);
3374  }
3375  m_MaxMessages = max_size;
3376 }
3377 
3378 
3380 {
3381  if ( m_Messages.get() && m_Messages->size() < m_MaxMessages) {
3382  m_Messages->push_back(message);
3383  }
3384 }
3385 
3386 
3388 {
3389  if ( !m_Messages.get() || m_Messages->empty() ) {
3390  return;
3391  }
3392  CTeeDiagHandler* tee = dynamic_cast<CTeeDiagHandler*>(&handler);
3393  if (tee && !tee->GetOriginalHandler()) {
3394  // Tee over STDERR - flushing will create duplicate messages
3395  return;
3396  }
3397  unique_ptr<TMessages> tmp(m_Messages.release());
3398  //ERR_POST_X(1, Note << "***** BEGIN COLLECTED MESSAGES *****");
3399  NON_CONST_ITERATE(TMessages, it, *tmp.get()) {
3400  it->m_NoTee = true; // Do not tee duplicate messages to console.
3401  handler.Post(*it);
3402  if (it->m_Flags & eDPF_IsConsole) {
3403  handler.PostToConsole(*it);
3404  }
3405  }
3406  //ERR_POST_X(2, Note << "***** END COLLECTED MESSAGES *****");
3407  m_Messages.reset(tmp.release());
3408 }
3409 
3410 
3412 {
3413  m_Messages.reset();
3414 }
3415 
3416 
3417 // Diagnostics setup
3418 
3419 static const char* kRootLog = "/log/";
3420 
3422 {
3423  static const char* kToolkitRcPath = "/etc/toolkitrc";
3424  static const char* kWebDirToPort = "Web_dir_to_port";
3425 
3426  string log_path = kRootLog;
3427 
3428  string exe_path = CFile(app.GetProgramExecutablePath()).GetDir();
3429  CNcbiIfstream is(kToolkitRcPath, ios::binary);
3430  CNcbiRegistry reg(is);
3431  list<string> entries;
3433  size_t min_pos = exe_path.length();
3434  string web_dir;
3435  // Find the first dir name corresponding to one of the entries
3436  ITERATE(list<string>, it, entries) {
3437  if (!it->empty() && (*it)[0] != '/') {
3438  // not an absolute path
3439  string mask = "/" + *it;
3440  if (mask[mask.length() - 1] != '/') {
3441  mask += "/";
3442  }
3443  size_t pos = exe_path.find(mask);
3444  if (pos < min_pos) {
3445  min_pos = pos;
3446  web_dir = *it;
3447  }
3448  }
3449  else {
3450  // absolute path
3451  if (exe_path.substr(0, it->length()) == *it) {
3452  web_dir = *it;
3453  break;
3454  }
3455  }
3456  }
3457  if ( !web_dir.empty() ) {
3458  return log_path + reg.GetString(kWebDirToPort, web_dir, kEmptyStr);
3459  }
3460  // Could not find a valid web-dir entry, use /log/port or empty string
3461  // to try /log/srv later.
3462  const TXChar* port = NcbiSys_getenv(_TX("SERVER_PORT"));
3463  return port ? log_path + string(_T_CSTRING(port)) : kEmptyStr;
3464 }
3465 
3466 
3467 typedef NCBI_PARAM_TYPE(Log, Truncate) TLogTruncateParam;
3468 
3470 {
3471  return TLogTruncateParam::GetDefault();
3472 }
3473 
3474 
3476 {
3477  TLogTruncateParam::SetDefault(value);
3478 }
3479 
3480 
3481 bool OpenLogFileFromConfig(const string& logname)
3482 {
3483  if ( !logname.empty() ) {
3484  if (NCBI_PARAM_TYPE(Log, NoCreate)::GetDefault() && !CDirEntry(logname).Exists() ) {
3485  return false;
3486  }
3487  return SetLogFile(logname, eDiagFile_All, true);
3488  }
3489  return false;
3490 }
3491 
3492 
3494 {
3495  if (!s_FinishedSetupDiag) {
3496  SetupDiag();
3497  }
3498 }
3499 
3500 
3502 {
3504  s_FinishedSetupDiag = true;
3505 }
3506 
3507 
3508 // Load string value from config if not null, or from the environment.
3509 static string s_GetLogConfigString(const CTempString name,
3510  const CTempString defval,
3512 {
3513  if ( config ) {
3514  return config->GetString("LOG", name, defval);
3515  }
3516  string envname = "NCBI_CONFIG__LOG__";
3517  envname += name;
3518  const TXChar* val = NcbiSys_getenv(_T_XCSTRING(envname));
3519  return val ? CTempString(_T_STDSTRING(val)) : defval;
3520 }
3521 
3522 
3523 // Load bool value from config if not null, or from the environment.
3524 static bool s_GetLogConfigBool(const CTempString name,
3525  bool defval,
3527 {
3528  if ( config ) {
3529  return config->GetBool("LOG", name, defval);
3530  }
3531  string envname = "NCBI_CONFIG__LOG__";
3532  envname += name;
3533  const TXChar* val = NcbiSys_getenv(_T_XCSTRING(envname));
3534  if ( val ) {
3535  try {
3537  }
3538  catch (const CStringException&) {
3539  }
3540  }
3541  return defval;
3542 }
3543 
3544 
3547  EDiagCollectMessages collect,
3548  const char* cmd_logfile)
3549 {
3551 
3553 
3554  // Check severity level change status now.
3555  // This used to be done in SetDiag(), but if the first logging event is an
3556  // Extra(), new post format is enabled and post level is Trace, the initialization
3557  // results in infinite recursion. To prevent this, call this as soon as possible,
3558  // before any logging is done.
3559  if ( CDiagBuffer::sm_PostSeverityChange == eDiagSC_Unknown ) {
3560  CDiagBuffer::GetSeverityChangeEnabledFirstTime();
3561  }
3562 
3564  // Initialize message collecting
3565  if (collect == eDCM_Init) {
3566  ctx.InitMessages();
3567  }
3568  else if (collect == eDCM_InitNoLimit) {
3569  ctx.InitMessages(size_t(-1));
3570  }
3571 
3572  /*
3573  The default order of checking possible log locations is:
3574 
3575  1. CMD - '-logfile <filename>' command line arg
3576  2. ENV - NCBI_CONFIG__LOG__FILE (or [Log]/File)
3577  3. LOG - /log/ if writable
3578  4. Other locations depending on 'ds' flag (e.g. current directory)
3579 
3580  IgnoreEnvArg: if CMD should be checked before (true) or after (false) ENV/LOG.
3581  TryRootLogFirst: if LOG should be checked berofe (true) or after (false) ENV.
3582 
3583  The resulting order is:
3584 
3585  IgnoreEnvArg: | true | false
3586  -------------------+-------------------+---------------
3587  TryRootLogFirst: | |
3588  true | CMD, LOG, ENV | LOG, ENV, CMD
3589  false | CMD, ENV, LOG | ENV, LOG, CMD
3590 
3591  Successfull opening of CMD/ENV/LOG also overrides any eDS_* flags except eDS_User.
3592  */
3593 
3594  bool log_set = false;
3595  bool to_applog = false;
3596  string old_log_name;
3597  string new_log_name;
3598 
3599  CDiagHandler* old_handler = GetDiagHandler();
3600  if ( old_handler ) {
3601  old_log_name = old_handler->GetLogName();
3602  }
3603 
3604  string config_logfile = s_GetLogConfigString("FILE", kEmptyStr, config);
3605  if ( config_logfile.empty() ) {
3606  // Try the old-style name
3607  config_logfile = s_GetLogConfigString("File", kEmptyStr, config);
3608  }
3609  bool cmdline_first = s_GetLogConfigBool("IgnoreEnvArg", true, config);
3610  bool applog_first = s_GetLogConfigBool("TryRootLogFirst", false, config);
3611 
3612  if (ds != eDS_User) {
3613  // If cmdline_first is not set, it will be checked later, after
3614  // checking all other possibilities.
3615  if (cmdline_first && cmd_logfile) {
3616  if ( SetLogFile(cmd_logfile, eDiagFile_All) ) {
3617  log_set = true;
3618  new_log_name = cmd_logfile;
3619  }
3620  }
3621  // If applog_first is set, config will be checked later for eDS_ToStdlog
3622  // and eDS_Default but only if /log is not available.
3623  if (!log_set && !applog_first && !config_logfile.empty()) {
3624  if ( OpenLogFileFromConfig(config_logfile) ) {
3625  log_set = true;
3626  new_log_name = config_logfile;
3627  }
3628  }
3629  // The following three eDS_* options should check /log/* before using -logfile.
3630  if (!log_set && !cmdline_first && cmd_logfile &&
3631  ds != eDS_Default && ds != eDS_ToStdlog && ds != eDS_ToSyslog) {
3632  if ( SetLogFile(cmd_logfile, eDiagFile_All) ) {
3633  log_set = true;
3634  new_log_name = cmd_logfile;
3635  }
3636  }
3637  }
3638 
3639  if ( !log_set ) {
3640  switch ( ds ) {
3641  case eDS_ToStdout:
3642  if (old_log_name != kLogName_Stdout) {
3644  SetDiagHandler(new CStreamDiagHandler(&cout, true, kLogName_Stdout), true);
3645  log_set = true;
3646  new_log_name = kLogName_Stdout;
3647  }
3648  break;
3649  case eDS_ToStderr:
3650  if (old_log_name != kLogName_Stderr) {
3652  SetDiagHandler(new CStreamDiagHandler(&cerr, true, kLogName_Stderr), true);
3653  log_set = true;
3654  new_log_name = kLogName_Stderr;
3655  }
3656  break;
3657  case eDS_ToMemory:
3658  if (old_log_name != kLogName_Memory) {
3659  ctx.InitMessages(size_t(-1));
3660  SetDiagStream(0, false, 0, 0, kLogName_Memory);
3661  log_set = true;
3662  new_log_name = kLogName_Memory;
3663  }
3664  collect = eDCM_NoChange; // prevent flushing to memory
3665  break;
3666  case eDS_Disable:
3667  if (old_log_name != kLogName_None) {
3668  SetDiagStream(0, false, 0, 0, kLogName_None);
3669  log_set = true;
3670  new_log_name = kLogName_None;
3671  }
3672  break;
3673  case eDS_User:
3674  collect = eDCM_Discard;
3675  break;
3676  case eDS_AppSpecific:
3677  collect = eDCM_Discard;
3678  break;
3679  case eDS_ToSyslog:
3680  if (old_log_name != CSysLog::kLogName_Syslog) {
3681  try {
3683  SetDiagHandler(new CSysLog);
3684  log_set = true;
3685  new_log_name = CSysLog::kLogName_Syslog;
3686  break;
3687  } catch (...) {
3688  // fall through
3689  }
3690  } else {
3691  break;
3692  }
3693  case eDS_ToStdlog:
3694  case eDS_Default:
3695  {
3696  // When using applog, create separate log file for each
3697  // user to avoid permission problems.
3698  string euid;
3699 #if defined(NCBI_OS_UNIX)
3700  euid = "." + NStr::NumericToString(geteuid());
3701 #endif
3702  string log_base;
3703  string def_log_dir;
3704  {{
3706  if ( app ) {
3707  log_base = app->GetProgramExecutablePath();
3708  def_log_dir = GetDefaultLogLocation(*app);
3709  }
3710  }}
3711  if ( !log_base.empty() ) {
3712  log_base = CFile(log_base).GetBase() + euid + ".log";
3713  string log_name;
3714  // Try /log/<port>
3715  if ( !def_log_dir.empty() ) {
3716  log_name = CFile::ConcatPath(def_log_dir, log_base);
3717  if ( SetLogFile(log_name) ) {
3718  log_set = true;
3719  new_log_name = log_name;
3720  to_applog = true;
3721  break;
3722  }
3723  }
3724  // Try /log/srv if port is unknown or not writable
3725  log_name = CFile::ConcatPath(CFile::ConcatPath(kRootLog, "srv"), log_base);
3726  if ( SetLogFile(log_name) ) {
3727  log_set = true;
3728  new_log_name = log_name;
3729  to_applog = true;
3730  break;
3731  }
3732  // Have we skipped config_logfile above?
3733  if (applog_first &&
3734  OpenLogFileFromConfig(config_logfile)) {
3735  log_set = true;
3736  new_log_name = config_logfile;
3737  break;
3738  }
3739  // Try to switch to /log/fallback/
3740  log_name = CFile::ConcatPath(CFile::ConcatPath(kRootLog, "fallback"), log_base);
3741  if ( SetLogFile(log_name) ) {
3742  log_set = true;
3743  new_log_name = log_name;
3744  to_applog = true;
3745  break;
3746  }
3747  // Try cwd/ for eDS_ToStdlog only
3748  if (ds == eDS_ToStdlog) {
3749  // Don't include euid in file name when using cwd.
3750  log_name = CFile::ConcatPath(".", CFile(log_base).GetBase() + ".log");
3751  if ( SetLogFile(log_name, eDiagFile_All) ) {
3752  log_set = true;
3753  new_log_name = log_name;
3754  break;
3755  }
3756  }
3757  _TRACE_X(3, "Failed to set log file to " +
3758  CFile::NormalizePath(log_name));
3759  }
3760  // Have we skipped cmd_logfile above?
3761  if (!log_set && !cmdline_first && cmd_logfile) {
3762  if ( SetLogFile(cmd_logfile, eDiagFile_All) ) {
3763  log_set = true;
3764  new_log_name = cmd_logfile;
3765  break;
3766  }
3767  }
3768  // No command line and no base name.
3769  // Try to switch to /log/fallback/UNKNOWN.<euid>
3770  if (!log_set && log_base.empty()) {
3771  string default_fallback = CFile::ConcatPath(kRootLog, "fallback/UNKNOWN.log");
3772  if ( SetLogFile(default_fallback + euid) ) {
3773  log_set = true;
3774  new_log_name = default_fallback;
3775  to_applog = true;
3776  break;
3777  }
3778  _TRACE_X(4, "Failed to set log file to " <<
3779  CFile::NormalizePath(default_fallback));
3780  }
3781  const char* log_name = TTeeToStderr::GetDefault() ?
3783  if (!log_set && old_log_name != log_name) {
3786  true, kLogName_Stderr), true);
3787  log_set = true;
3788  new_log_name = log_name;
3789  }
3790  break;
3791  }
3792  default:
3793  ERR_POST_X(5, Warning << "Unknown EAppDiagStream value");
3794  _ASSERT(0);
3795  break;
3796  }
3797  }
3798 
3799  // Unlock severity level
3800  SetApplogSeverityLocked(false);
3801  if ( to_applog ) {
3802  ctx.SetOldPostFormat(false);
3803  s_LogSizeLimit->Set(0); // No log size limit
3805  // Lock severity level
3807  }
3808  else {
3809  // Disable throttling
3810  ctx.SetLogRate_Limit(eLogRate_App, CRequestRateControl::kNoLimit);
3811  ctx.SetLogRate_Limit(eLogRate_Err, CRequestRateControl::kNoLimit);
3813  }
3814 
3815  CDiagHandler* new_handler = GetDiagHandler();
3816  // Flush collected messages to the log if either its name has changed
3817  // or log file truncation is enabled.
3818  if (log_set && new_handler && new_handler->GetLogName() == old_log_name) {
3819  bool is_file = dynamic_cast<CFileHandleDiagHandler*>(new_handler) ||
3820  dynamic_cast<CFileDiagHandler*>(new_handler);
3821  log_set = log_set && is_file && GetLogTruncate();
3822  }
3823 
3824  if (collect == eDCM_Flush) {
3825  // Flush and discard
3826  if ( log_set && new_handler ) {
3827  ctx.FlushMessages(*new_handler);
3828  }
3829  collect = eDCM_Discard;
3830  }
3831  else if (collect == eDCM_NoChange) {
3832  // Flush but don't discard
3833  if ( log_set && new_handler ) {
3834  ctx.FlushMessages(*new_handler);
3835  }
3836  }
3837  if (collect == eDCM_Discard) {
3838  ctx.DiscardMessages();
3839  }
3840 
3841  // Refresh rate controls
3842  ctx.ResetLogRates();
3843 
3845 }
3846 
3847 
3849 {
3850  static CAtomicCounter s_ProcessPostCount;
3851  return (TCount)(inc == ePostNumber_Increment ?
3852  s_ProcessPostCount.Add(1) : s_ProcessPostCount.Get());
3853 }
3854 
3855 
3857 {
3859 }
3860 
3861 
3863 {
3865 }
3866 
3867 
3869 {
3870  return GetLogFile().substr(0, 5) == kRootLog;
3871 }
3872 
3873 
3875 {
3876  // Make the context live longer than other diag safe-statics
3877  // and +1 longer than TLS safe statics which print app stop
3878  // from their cleanup.
3879  static CSafeStatic<CDiagContext> s_DiagContext(
3881 
3882  return s_DiagContext.Get();
3883 }
3884 
3885 
3886 ///////////////////////////////////////////////////////
3887 // CNcbiLogFields::
3888 
3889 #ifdef NCBI_LOG_FIELDS_CUSTOM
3890 NCBI_PARAM_DECL(string, Log, Ncbi_Log_Fields_Custom);
3891 NCBI_PARAM_DEF_EX(string, Log, Ncbi_Log_Fields_Custom, "",
3892  eParam_NoThread, NCBI_LOG_FIELDS_CUSTOM);
3893 typedef NCBI_PARAM_TYPE(Log, Ncbi_Log_Fields_Custom) TCustomLogFields;
3894 #endif
3895 
3896 
3898  : m_Source(source)
3899 {
3900  const TXChar* env_fields = NcbiSys_getenv(_TX("NCBI_LOG_FIELDS"));
3901  if ( env_fields ) {
3902  string fields = _T_CSTRING(env_fields);
3903  NStr::ToLower(fields);
3904  NStr::ReplaceInPlace(fields, "_", "-");
3906  }
3907 #ifdef NCBI_LOG_FIELDS_CUSTOM
3908  string custom_fields = TCustomLogFields::GetDefault();
3909  NStr::ToLower(custom_fields);
3910  NStr::ReplaceInPlace(custom_fields, "_", "-");
3911  NStr::Split(custom_fields, " ", m_Fields, NStr::fSplit_Tokenize);
3912 #endif
3913 }
3914 
3915 
3917 {
3918 }
3919 
3920 
3921 void CNcbiLogFields::x_Match(const string& name, const string& value, CDiagContext_Extra& extra) const
3922 {
3923  ITERATE(TFields, it, m_Fields) {
3924  if ( it->empty() ) continue; // Skip empty entries since they match anything.
3925  if (NStr::MatchesMask(name, *it, NStr::eNocase)) {
3926  extra.Print((m_Source.empty() ? name : m_Source + "." + name), value);
3927  break; // Stop if a match is found.
3928  }
3929  }
3930 }
3931 
3932 
3933 ///////////////////////////////////////////////////////
3934 // CDiagBuffer::
3935 
3936 #if defined(NDEBUG)
3937 EDiagSev CDiagBuffer::sm_PostSeverity = eDiag_Error;
3938 #else
3939 EDiagSev CDiagBuffer::sm_PostSeverity = eDiag_Warning;
3940 #endif
3941 
3942 EDiagSevChange CDiagBuffer::sm_PostSeverityChange = eDiagSC_Unknown;
3943  // to be set on first request
3944 
3950 static bool s_DiagPostFlagsInitialized = false;
3951 
3952 inline
3953 TDiagPostFlags& CDiagBuffer::sx_GetPostFlags(void)
3954 {
3958  }
3959  return s_PostFlags;
3960 }
3961 
3962 
3963 TDiagPostFlags& CDiagBuffer::s_GetPostFlags(void)
3964 {
3965  return sx_GetPostFlags();
3966 }
3967 
3968 
3969 TDiagPostFlags CDiagBuffer::sm_TraceFlags = eDPF_Trace;
3970 
3971 bool CDiagBuffer::sm_IgnoreToDie = false;
3972 EDiagSev CDiagBuffer::sm_DieSeverity = eDiag_Fatal;
3973 
3974 EDiagTrace CDiagBuffer::sm_TraceDefault = eDT_Default;
3975 bool CDiagBuffer::sm_TraceEnabled; // to be set on first request
3976 
3977 
3978 const char* CDiagBuffer::sm_SeverityName[eDiag_Trace+1] = {
3979  "Info", "Warning", "Error", "Critical", "Fatal", "Trace" };
3980 
3981 
3982 NCBI_PARAM_ENUM_DECL(EDiagSev, DEBUG, Stack_Trace_Level);
3984 {
3985  {"Trace", eDiag_Trace},
3986  { "Info", eDiag_Info },
3987  { "Warning", eDiag_Warning },
3988  { "Error", eDiag_Error },
3989  { "Critical", eDiag_Critical },
3990  { "Fatal", eDiag_Fatal }
3991 };
3993  DEBUG,
3994  Stack_Trace_Level,
3995  eDiag_Fatal,
3996  eParam_NoThread, // No per-thread values
3997  DEBUG_STACK_TRACE_LEVEL);
3998 
3999 
4000 void* InitDiagHandler(void)
4001 {
4003 
4004  static bool s_DiagInitialized = false;
4005  if (!s_DiagInitialized) {
4007 #ifdef NCBI_OS_MSWIN
4008  // Check environment variable for silent exit, suppress popup messages if enabled.
4009  // _ASSERT uses NCBI Diag API, and this allow it to work properly.
4010  const TXChar* value = NcbiSys_getenv(_TX("DIAG_SILENT_ABORT"));
4011  if (value && (*value == _TX('Y') || *value == _TX('y') || *value == _TX('1'))) {
4013  }
4014 #endif
4015  s_DiagInitialized = true;
4016  }
4017  return 0;
4018 }
4019 
4020 
4021 // For initialization only
4023 
4024 
4025 // MT-safe initialization of the default handler
4027 
4028 
4029 // Use s_DefaultHandler only for purposes of comparison, as installing
4030 // another handler will normally delete it.
4031 // NOTE: If SetDiagHandler is never called, the default handler will not
4032 // be destroyed on application termination. This is a tradeoff for having
4033 // the handler always available.
4035 CDiagHandler* CDiagBuffer::sm_Handler = s_DefaultHandler;
4036 bool CDiagBuffer::sm_CanDeleteHandler = true;
4037 CDiagErrCodeInfo* CDiagBuffer::sm_ErrCodeInfo = 0;
4038 bool CDiagBuffer::sm_CanDeleteErrCodeInfo = false;
4039 
4040 
4042 {
4044  static bool s_DefaultDiagHandlerInitialized = false;
4045  if ( !s_DefaultDiagHandlerInitialized ) {
4046  s_DefaultDiagHandlerInitialized = true;
4048  if ( TTeeToStderr::GetDefault() ) {
4049  // Need to tee?
4050  handler = new CTeeDiagHandler(handler, true);
4051  }
4052  return handler;
4053  }
4054  return s_DefaultHandler;
4055 }
4056 
4057 
4058 
4059 // Note: Intel Thread Checker detects a memory leak at the line:
4060 // m_Stream(new CNcbiOstrstream) below
4061 // This is not a fault of the toolkit code as soon as a code like:
4062 // int main() {
4063 // ostrstream * s = new ostrstream;
4064 // delete s;
4065 // return 0;
4066 // }
4067 // will also report memory leaks.
4068 // Test environment:
4069 // - Intel Thread Checker for Linux 3.1
4070 // - gcc 4.0.1, gcc 4.1.2, icc 10.1
4071 // - Linux64
4072 CDiagBuffer::CDiagBuffer(void)
4073  : m_Stream(new CNcbiOstrstream),
4074  m_InitialStreamFlags(m_Stream->flags()),
4075  m_InUse(false)
4076 {
4077  m_Diag = 0;
4078 }
4079 
4080 CDiagBuffer::~CDiagBuffer(void)
4081 {
4082 #if (_DEBUG > 1)
4083  if (m_Diag || m_Stream->pcount())
4084  Abort();
4085 #endif
4086  delete m_Stream;
4087  m_Stream = 0;
4088 }
4089 
4090 void CDiagBuffer::DiagHandler(SDiagMessage& mess)
4091 {
4092  bool is_console = (mess.m_Flags & eDPF_IsConsole) > 0;
4093  bool applog = (mess.m_Flags & eDPF_AppLog) > 0;
4094  bool is_printable = applog || SeverityPrintable(mess.m_Severity);
4095  if (!is_console && !is_printable) {
4096  return;
4097  }
4098  if ( CDiagBuffer::sm_Handler ) {
4100  if ( CDiagBuffer::sm_Handler ) {
4101  // The mutex must be locked before approving.
4102  CDiagBuffer& diag_buf = GetDiagBuffer();
4103  bool show_warning = false;
4105  const CRequestContext& rctx = ctx.GetRequestContext();
4106  mess.m_Prefix = diag_buf.m_PostPrefix.empty() ?
4107  0 : diag_buf.m_PostPrefix.c_str();
4108  if (is_console) {
4109  // No throttling for console
4110  CDiagBuffer::sm_Handler->PostToConsole(mess);
4111  if ( !is_printable ) {
4112  return;
4113  }
4114  }
4115  if ( ctx.ApproveMessage(mess, &show_warning) ) {
4116  if (mess.m_Severity >= eDiag_Error &&
4117  mess.m_Severity != eDiag_Trace &&
4118  s_DisableAppLog->Get() &&
4119  rctx.x_LogHitIDOnError()) {
4120  const CNcbiDiag diag(DIAG_COMPILE_INFO);
4121  SDiagMessage phid_msg(eDiag_Error,
4122  0, 0,
4123  diag.GetFile(),
4124  diag.GetLine(),
4125  diag.GetPostFlags() | eDPF_AppLog,
4126  NULL,
4127  0, // Error code
4128  0, // Err subcode
4129  NULL,
4130  diag.GetModule(),
4131  diag.GetClass(),
4132  diag.GetFunction());
4133  phid_msg.m_Event = SDiagMessage::eEvent_Extra;
4134  phid_msg.m_ExtraArgs.push_back(SDiagMessage::TExtraArg(
4136  rctx.GetHitID()));
4137  CDiagBuffer::sm_Handler->Post(phid_msg);
4138  }
4139  CDiagBuffer::sm_Handler->Post(mess);
4140  }
4141  else if ( show_warning ) {
4142  // Substitute the original message with the error.
4143  // ERR_POST cannot be used here since nested posts
4144  // are blocked. Have to create the message manually.
4145  string limit_name = "error";
4146  CDiagContext::ELogRate_Type limit_type =
4148  if ( IsSetDiagPostFlag(eDPF_AppLog, mess.m_Flags) ) {
4149  limit_name = "applog";
4150  limit_type = CDiagContext::eLogRate_App;
4151  }
4152  else if (mess.m_Severity == eDiag_Info ||
4153  mess.m_Severity == eDiag_Trace) {
4154  limit_name = "trace";
4155  limit_type = CDiagContext::eLogRate_Trace;
4156  }
4157  string txt = "Maximum logging rate for " + limit_name + " ("
4158  + NStr::UIntToString(ctx.GetLogRate_Limit(limit_type))
4159  + " messages per "
4160  + NStr::UIntToString(ctx.GetLogRate_Period(limit_type))
4161  + " sec) exceeded, suspending the output.";
4162  const CNcbiDiag diag(DIAG_COMPILE_INFO);
4163  SDiagMessage err_msg(eDiag_Error,
4164  txt.c_str(), txt.length(),
4165  diag.GetFile(),
4166  diag.GetLine(),
4167  diag.GetPostFlags(),
4168  NULL,
4169  err_code_x::eErrCodeX_Corelib_Diag, // Error code
4170  23, // Err subcode
4171  NULL,
4172  diag.GetModule(),
4173  diag.GetClass(),
4174  diag.GetFunction());
4175  CDiagBuffer::sm_Handler->Post(err_msg);
4176  return;
4177  }
4178  }
4179  }
4180  GetDiagContext().PushMessage(mess);
4181 }
4182 
4183 
4184 inline
4185 bool CDiagBuffer::SeverityDisabled(EDiagSev sev)
4186 {
4187  CDiagContextThreadData& thr_data =
4189  CDiagCollectGuard* guard = thr_data.GetCollectGuard();
4190  EDiagSev post_sev = AdjustApplogPrintableSeverity(sm_PostSeverity);
4191  bool allow_trace = GetTraceEnabled();
4192  if ( guard ) {
4193  post_sev = guard->GetCollectSeverity();
4194  allow_trace = post_sev == eDiag_Trace;
4195  }
4196  if (sev == eDiag_Trace && !allow_trace) {
4197  return true; // trace is disabled
4198  }
4199  if (post_sev == eDiag_Trace && allow_trace) {
4200  return false; // everything is enabled
4201  }
4202  return (sev < post_sev) && (sev < sm_DieSeverity || sm_IgnoreToDie);
4203 }
4204 
4205 
4206 inline
4207 bool CDiagBuffer::SeverityPrintable(EDiagSev sev)
4208 {
4209  CDiagContextThreadData& thr_data =
4211  CDiagCollectGuard* guard = thr_data.GetCollectGuard();
4212  EDiagSev post_sev = AdjustApplogPrintableSeverity(sm_PostSeverity);
4213  bool allow_trace = GetTraceEnabled();
4214  if ( guard ) {
4215  post_sev = AdjustApplogPrintableSeverity(guard->GetPrintSeverity());
4216  allow_trace = post_sev == eDiag_Trace;
4217  }
4218  if (sev == eDiag_Trace && !allow_trace) {
4219  return false; // trace is disabled
4220  }
4221  if (post_sev == eDiag_Trace && allow_trace) {
4222  return true; // everything is enabled
4223  }
4224  return !((sev < post_sev) && (sev < sm_DieSeverity || sm_IgnoreToDie));
4225 }
4226 
4227 
4228 bool CDiagBuffer::SetDiag(const CNcbiDiag& diag)
4229 {
4230  if ( m_InUse || !m_Stream ) {
4231  return false;
4232  }
4233 
4234  EDiagSev sev = diag.GetSeverity();
4235  bool is_console = (diag.GetPostFlags() & eDPF_IsConsole) > 0;
4236  if (!is_console && SeverityDisabled(sev)) {
4237  return false;
4238  }
4239 
4240  if (m_Diag != &diag) {
4241  if ( !IsOssEmpty(*m_Stream) ) {
4242  Flush();
4243  }
4244  m_Diag = &diag;
4245  }
4246 
4247  return true;
4248 }
4249 
4250 
4252 {
4253 public:
4254  CRecursionGuard(bool& flag) : m_Flag(flag) { m_Flag = true; }
4255  ~CRecursionGuard(void) { m_Flag = false; }
4256 private:
4257  bool& m_Flag;
4258 };
4259 
4260 
4262 {
4263  static bool Check();
4264  static SDiagMessage Report(EDiagSev& sev);
4265 
4266 private:
4267  static atomic<thread::id> sm_ThreadID;
4268  static atomic<bool> sm_Reported;
4269 };
4270 
4271 
4272 atomic<thread::id> SThreadsInSTBuild::sm_ThreadID;
4273 atomic<bool> SThreadsInSTBuild::sm_Reported;
4274 
4275 
4277 {
4278 #ifndef NCBI_THREADS
4279  thread::id stored_thread_id;
4280  thread::id this_thread_id = this_thread::get_id();
4281 
4282  // If this thread has just initialized sm_ThreadID
4283  if (sm_ThreadID.compare_exchange_strong(stored_thread_id, this_thread_id)) return false;
4284 
4285  // If sm_ThreadID contains same thread ID
4286  if (stored_thread_id == this_thread_id) return false;
4287 
4288  bool reported = false;
4289 
4290  // Whether to report this (or it has already been reported)
4291  if (sm_Reported.compare_exchange_strong(reported, true)) return true;
4292 #endif
4293 
4294  return false;
4295 }
4296 
4297 
4299 {
4300 #ifdef _DEBUG
4301  sev = eDiag_Fatal;
4302 #else
4303  sev = eDiag_Critical;
4304 #endif
4305 
4306  const auto msg = "Detected different threads using C++ Toolkit built in single thread mode."sv;
4307  const CNcbiDiag diag(DIAG_COMPILE_INFO);
4308  return SDiagMessage(
4309  sev,
4310  msg.data(),
4311  msg.length(),
4312  diag.GetFile(),
4313  diag.GetLine(),
4314  diag.GetPostFlags(),
4315  nullptr,
4316  0,
4317  0,
4318  nullptr,
4319  diag.GetModule(),
4320  diag.GetClass(),
4321  diag.GetFunction());
4322 }
4323 
4324 
4325 void CDiagBuffer::Flush(void)
4326 {
4327  if ( m_InUse || !m_Diag ) {
4328  if ( !m_InUse && m_Stream && !IsOssEmpty(*m_Stream) ) {
4329  string message = CNcbiOstrstreamToString(*m_Stream);
4330  // Can not use Reset() without CNcbiDiag.
4331  m_Stream->rdbuf()->PUBSEEKOFF(0, IOS_BASE::beg, IOS_BASE::out);
4332  // _TRACE("Discarding junk data from CDiagBuffer: " << message);
4333  }
4334  return;
4335  }
4336  CRecursionGuard guard(m_InUse);
4337 
4338  EDiagSev sev = m_Diag->GetSeverity();
4339  bool is_console = (m_Diag->GetPostFlags() & eDPF_IsConsole) != 0;
4340  bool is_disabled = SeverityDisabled(sev);
4341 
4342  // Do nothing if diag severity is lower than allowed.
4343  if (!is_console && is_disabled) {
4344  return;
4345  }
4346 
4347  string message = CNcbiOstrstreamToString(*m_Stream);
4348 
4349  TDiagPostFlags flags = m_Diag->GetPostFlags();
4350  if (sev == eDiag_Trace) {
4351  flags |= sm_TraceFlags;
4352  } else if (sev == eDiag_Fatal) {
4353  // normally only happens once, so might as well pull everything
4354  // in for the record...
4355  flags |= sm_TraceFlags | eDPF_Trace;
4356  }
4357 
4358  if ( m_Diag->CheckFilters() ) {
4359  SDiagMessage mess(sev, message.data(), message.size(),
4360  m_Diag->GetFile(),
4361  m_Diag->GetLine(),
4362  flags,
4363  NULL,
4364  m_Diag->GetErrorCode(),
4365  m_Diag->GetErrorSubCode(),
4366  NULL,
4367  m_Diag->GetModule(),
4368  m_Diag->GetClass(),
4369  m_Diag->GetFunction());
4370  PrintMessage(mess, *m_Diag);
4371  }
4372 
4373  if (SThreadsInSTBuild::Check()) {
4374  // Change severity and print error message
4375  auto mess = SThreadsInSTBuild::Report(sev);
4376  PrintMessage(mess, *m_Diag);
4377  }
4378 
4379 #if defined(NCBI_COMPILER_KCC)
4380  // KCC's implementation of "freeze(false)" makes the ostrstream buffer
4381  // stuck. We need to replace the frozen stream with the new one.
4382  delete ostr;
4383  m_Stream = new CNcbiOstrstream;
4384 #else
4385  // reset flags to initial value
4386  m_Stream->flags(m_InitialStreamFlags);
4387 # ifdef NCBI_SHUN_OSTRSTREAM
4388  // m_Stream->rdbuf()->PUBSEEKOFF(0, IOS_BASE::beg);
4389  m_Stream->str(kEmptyStr);
4390 # endif
4391 #endif
4392 
4393  Reset(*m_Diag);
4394 
4395  if (sev >= sm_DieSeverity && sev != eDiag_Trace && !sm_IgnoreToDie) {
4396  m_Diag = 0;
4397 
4398 #ifdef NCBI_COMPILER_MSVC
4399  if (NCBI_PARAM_TYPE(Diag, Assert_On_Abort)::GetDefault() ) {
4400  int old_mode = _set_error_mode(_OUT_TO_MSGBOX);
4401  _ASSERT(false); // Show assertion dialog
4402  _set_error_mode(old_mode);
4403  }
4404  else {
4405  Abort();
4406  }
4407 #else // NCBI_COMPILER_MSVC
4408  Abort();
4409 #endif // NCBI_COMPILER_MSVC
4410  }
4411 }
4412 
4413 
4414 void CDiagBuffer::PrintMessage(SDiagMessage& mess, const CNcbiDiag& diag)
4415 {
4416  EDiagSev sev = diag.GetSeverity();
4417  if (!SeverityPrintable(sev)) {
4418  CDiagContextThreadData& thr_data =
4420  bool can_collect = thr_data.GetCollectGuard() != NULL;
4421  bool is_console = (diag.GetPostFlags() & eDPF_IsConsole) != 0;
4422  bool is_disabled = SeverityDisabled(sev);
4423  if (!is_disabled || (is_console && can_collect)) {
4424  thr_data.CollectDiagMessage(mess);
4425  Reset(diag);
4426  // The message has been collected, don't print to
4427  // the console now.
4428  return;
4429  }
4430  }
4431  if ( !diag.GetOmitStackTrace() ) {
4432  static CSafeStatic<NCBI_PARAM_TYPE(DEBUG, Stack_Trace_Level)> s_StackTraceLevel;
4433  EDiagSev stack_sev = s_StackTraceLevel->Get();
4434  mess.m_PrintStackTrace = (sev == stack_sev) || (sev > stack_sev && sev != eDiag_Trace);
4435  }
4436  DiagHandler(mess);
4437 }
4438 
4439 
4440 bool CDiagBuffer::GetTraceEnabledFirstTime(void)
4441 {
4444  if (str && *str) {
4445  sm_TraceDefault = eDT_Enable;
4446  } else {
4447  sm_TraceDefault = eDT_Disable;
4448  }
4449  sm_TraceEnabled = (sm_TraceDefault == eDT_Enable);
4450  return sm_TraceEnabled;
4451 }
4452 
4453 
4454 bool CDiagBuffer::GetSeverityChangeEnabledFirstTime(void)
4455 {
4456  if ( sm_PostSeverityChange != eDiagSC_Unknown ) {
4457  return sm_PostSeverityChange == eDiagSC_Enable;
4458  }
4460  EDiagSev sev;
4461  if (str && *str && CNcbiDiag::StrToSeverityLevel(_T_CSTRING(str), sev)) {
4462  SetDiagFixedPostLevel(sev);
4463  } else {
4464  sm_PostSeverityChange = eDiagSC_Enable;
4465  }
4466  return sm_PostSeverityChange == eDiagSC_Enable;
4467 }
4468 
4469 
4470 void CDiagBuffer::UpdatePrefix(void)
4471 {
4472  m_PostPrefix.erase();
4473  ITERATE(TPrefixList, prefix, m_PrefixList) {
4474  if (prefix != m_PrefixList.begin()) {
4475  m_PostPrefix += "::";
4476  }
4477  m_PostPrefix += *prefix;
4478  }
4479 }
4480 
4481 
4482 ///////////////////////////////////////////////////////
4483 // CDiagMessage::
4484 
4485 
4487  const char* buf, size_t len,
4488  const char* file, size_t line,
4489  TDiagPostFlags flags, const char* prefix,
4490  int err_code, int err_subcode,
4491  const char* err_text,
4492  const char* module,
4493  const char* nclass,
4494  const char* function)
4495  : m_Event(eEvent_Start),
4496  m_TypedExtra(false),
4497  m_NoTee(false),
4498  m_PrintStackTrace(false),
4499  m_Data(0),
4500  m_Format(eFormat_Auto),
4501  m_AllowBadExtraNames(false)
4502 {
4503  m_Severity = severity;
4504  m_Buffer = buf;
4505  m_BufferLen = len;
4506  m_File = file;
4507  m_Line = line;
4508  m_Flags = flags;
4509  m_Prefix = prefix;
4510  m_ErrCode = err_code;
4511  m_ErrSubCode = err_subcode;
4512  m_ErrText = err_text;
4513  m_Module = module;
4514  m_Class = nclass;
4515  m_Function = function;
4516 
4517  CDiagContextThreadData& thr_data =
4519  CRequestContext& rq_ctx = thr_data.GetRequestContext();
4521  m_TID = thr_data.GetTID();
4522  EDiagAppState app_state = GetAppState();
4523  switch (app_state) {
4525  case eDiagAppState_Request:
4527  if ( rq_ctx.GetAutoIncRequestIDOnPost() ) {
4528  rq_ctx.SetRequestID();
4529  }
4530  m_RequestId = rq_ctx.GetRequestID();
4531  break;
4532  default:
4533  m_RequestId = 0;
4534  }
4537 }
4538 
4539 
4540 SDiagMessage::SDiagMessage(const string& message, bool* result)
4541  : m_Severity(eDiagSevMin),
4542  m_Buffer(0),
4543  m_BufferLen(0),
4544  m_File(0),
4545  m_Module(0),
4546  m_Class(0),
4547  m_Function(0),
4548  m_Line(0),
4549  m_ErrCode(0),
4550  m_ErrSubCode(0),
4551  m_Flags(0),
4552  m_Prefix(0),
4553  m_ErrText(0),
4554  m_PID(0),
4555  m_TID(0),
4556  m_ProcPost(0),
4557  m_ThrPost(0),
4558  m_RequestId(0),
4559  m_Event(eEvent_Start),
4560  m_TypedExtra(false),
4561  m_NoTee(false),
4562  m_PrintStackTrace(false),
4563  m_Data(0),
4564  m_Format(eFormat_Auto),
4565  m_AllowBadExtraNames(false)
4566 {
4567  bool res = ParseMessage(message);
4568  if ( result ) {
4569  *result = res;
4570  }
4571 }
4572 
4573 
4575 {
4576  if ( m_Data ) {
4577  delete m_Data;
4578  }
4579 }
4580 
4581 
4583  : m_Severity(eDiagSevMin),
4584  m_Buffer(0),
4585  m_BufferLen(0),
4586  m_File(0),
4587  m_Module(0),
4588  m_Class(0),
4589  m_Function(0),
4590  m_Line(0),
4591  m_ErrCode(0),
4592  m_ErrSubCode(0),
4593  m_Flags(0),
4594  m_Prefix(0),
4595  m_ErrText(0),
4596  m_PID(0),
4597  m_TID(0),
4598  m_ProcPost(0),
4599  m_ThrPost(0),
4600  m_RequestId(0),
4601  m_Event(eEvent_Start),
4602  m_TypedExtra(false),
4603  m_NoTee(false),
4604  m_PrintStackTrace(false),
4605  m_Data(0),
4606  m_Format(eFormat_Auto),
4607  m_AllowBadExtraNames(false)
4608 {
4609  *this = message;
4610 }
4611 
4612 
4614 {
4615  if (&message != this) {
4616  m_Format = message.m_Format;
4618  if ( message.m_Data ) {
4619  m_Data = new SDiagMessageData(*message.m_Data);
4620  m_Data->m_Host = message.m_Data->m_Host;
4621  m_Data->m_Client = message.m_Data->m_Client;
4622  m_Data->m_Session = message.m_Data->m_Session;
4623  m_Data->m_AppName = message.m_Data->m_AppName;
4624  m_Data->m_AppState = message.m_Data->m_AppState;
4625  }
4626  else {
4628  if (message.m_Buffer) {
4629  m_Data->m_Message =
4630  string(message.m_Buffer, message.m_BufferLen);
4631  }
4632  if ( message.m_File ) {
4633  m_Data->m_File = message.m_File;
4634  }
4635  if ( message.m_Module ) {
4636  m_Data->m_Module = message.m_Module;
4637  }
4638  if ( message.m_Class ) {
4639  m_Data->m_Class = message.m_Class;
4640  }
4641  if ( message.m_Function ) {
4642  m_Data->m_Function = message.m_Function;
4643  }
4644  if ( message.m_Prefix ) {
4645  m_Data->m_Prefix = message.m_Prefix;
4646  }
4647  if ( message.m_ErrText ) {
4648  m_Data->m_ErrText = message.m_ErrText;
4649  }
4650  }
4651  m_Severity = message.m_Severity;
4652  m_Line = message.m_Line;
4653  m_ErrCode = message.m_ErrCode;
4654  m_ErrSubCode = message.m_ErrSubCode;
4655  m_Flags = message.m_Flags;
4656  m_PID = message.m_PID;
4657  m_TID = message.m_TID;
4658  m_ProcPost = message.m_ProcPost;
4659  m_ThrPost = message.m_ThrPost;
4660  m_RequestId = message.m_RequestId;
4661  m_Event = message.m_Event;
4662  m_TypedExtra = message.m_TypedExtra;
4663  m_ExtraArgs.assign(message.m_ExtraArgs.begin(),
4664  message.m_ExtraArgs.end());
4665 
4666  m_Buffer = m_Data->m_Message.empty() ? 0 : m_Data->m_Message.c_str();
4667  m_BufferLen = m_Data->m_Message.empty() ? 0 : m_Data->m_Message.length();
4668  m_File = m_Data->m_File.empty() ? 0 : m_Data->m_File.c_str();
4669  m_Module = m_Data->m_Module.empty() ? 0 : m_Data->m_Module.c_str();
4670  m_Class = m_Data->m_Class.empty() ? 0 : m_Data->m_Class.c_str();
4671  m_Function = m_Data->m_Function.empty()
4672  ? 0 : m_Data->m_Function.c_str();
4673  m_Prefix = m_Data->m_Prefix.empty() ? 0 : m_Data->m_Prefix.c_str();
4674  m_ErrText = m_Data->m_ErrText.empty() ? 0 : m_Data->m_ErrText.c_str();
4675  }
4676  return *this;
4677 }
4678 
4679 
4680 Uint8 s_ParseInt(const string& message,
4681  size_t& pos, // start position
4682  size_t width, // fixed width or 0
4683  char sep) // trailing separator (throw if not found)
4684 {
4685  if (pos >= message.length()) {
4687  "Failed to parse diagnostic message");
4688  }
4689  Uint8 ret = 0;
4690  if (width > 0) {
4691  if (message[pos + width] != sep) {
4693  "Missing separator after integer");
4694  }
4695  }
4696  else {
4697  width = message.find(sep, pos);
4698  if (width == NPOS) {
4700  "Missing separator after integer");
4701  }
4702  width -= pos;
4703  }
4704 
4705  ret = NStr::StringToUInt8(CTempString(message.c_str() + pos, width));
4706  pos += width + 1;
4707  return ret;
4708 }
4709 
4710 
4711 CTempString s_ParseStr(const string& message,
4712  size_t& pos, // start position
4713  char sep, // separator
4714  bool optional = false) // do not throw if not found
4715 {
4716  if (pos >= message.length()) {
4718  "Failed to parse diagnostic message");
4719  }
4720  size_t pos1 = pos;
4721  pos = message.find(sep, pos1);
4722  if (pos == NPOS) {
4723  if ( !optional ) {
4725  "Failed to parse diagnostic message");
4726  }
4727  pos = pos1;
4728  return kEmptyStr;
4729  }
4730  if ( pos == pos1 + 1 && !optional ) {
4731  // The separator is in the next position, no empty string allowed
4733  "Failed to parse diagnostic message");
4734  }
4735  // remember end position of the string, skip separators
4736  size_t pos2 = pos;
4737  pos = message.find_first_not_of(sep, pos);
4738  if (pos == NPOS) {
4739  pos = message.length();
4740  }
4741  return CTempString(message.c_str() + pos1, pos2 - pos1);
4742 }
4743 
4744 
4745 static const char s_ExtraEncodeChars[256][4] = {
4746  "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07",
4747  "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F",
4748  "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17",
4749  "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F",
4750  "+", "!", "\"", "#", "$", "%25", "%26", "'",
4751  "(", ")", "*", "%2B", ",", "-", ".", "/",
4752  "0", "1", "2", "3", "4", "5", "6", "7",
4753  "8", "9", ":", ";", "<", "%3D", ">", "?",
4754  "@", "A", "B", "C", "D", "E", "F", "G",
4755  "H", "I", "J", "K", "L", "M", "N", "O",
4756  "P", "Q", "R", "S", "T", "U", "V", "W",
4757  "X", "Y", "Z", "[", "\\", "]", "^", "_",
4758  "`", "a", "b", "c", "d", "e", "f", "g",
4759  "h", "i", "j", "k", "l", "m", "n", "o",
4760  "p", "q", "r", "s", "t", "u", "v", "w",
4761  "x", "y", "z", "{", "|", "}", "~", "%7F",
4762  "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87",
4763  "%88", "%89", "%8A", "%8B", "%8C", "%8D", "%8E", "%8F",
4764  "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97",
4765  "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
4766  "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7",
4767  "%A8", "%A9", "%AA", "%AB", "%AC", "%AD", "%AE", "%AF",
4768  "%B0", "%B1", "%B2", "%B3", "%B4", "%B5", "%B6", "%B7",
4769  "%B8", "%B9", "%BA", "%BB", "%BC", "%BD", "%BE", "%BF",
4770  "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
4771  "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF",
4772  "%D0", "%D1", "%D2", "%D3", "%D4", "%D5", "%D6", "%D7",
4773  "%D8", "%D9", "%DA", "%DB", "%DC", "%DD", "%DE", "%DF",
4774  "%E0", "%E1", "%E2", "%E3", "%E4", "%E5", "%E6", "%E7",
4775  "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
4776  "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7",
4777  "%F8", "%F9", "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
4778 };
4779 
4780 
4781 inline
4782 bool x_IsEncodableChar(char c)
4783 {
4784  return s_ExtraEncodeChars[(unsigned char)c][0] != c ||
4785  s_ExtraEncodeChars[(unsigned char)c][1] != 0;
4786 }
4787 
4788 
4790 {
4791 public:
4792  virtual string Decode(const CTempString src, EStringType stype) const;
4793 };
4794 
4795 
4796 string CExtraDecoder::Decode(const CTempString src, EStringType stype) const
4797 {
4798  string str = src; // NStr::TruncateSpaces(src);
4799  size_t len = str.length();
4800  if ( !len && stype == eName ) {
4801  NCBI_THROW2(CStringException, eFormat,
4802  "Empty name in extra-arg", 0);
4803  }
4804 
4805  size_t dst = 0;
4806  for (size_t p = 0; p < len; dst++) {
4807  switch ( str[p] ) {
4808  case '%': {
4809  if (p + 2 > len) {
4810  NCBI_THROW2(CStringException, eFormat,
4811  "Inavild char in extra arg", p);
4812  }
4813  int n1 = NStr::HexChar(str[p+1]);
4814  int n2 = NStr::HexChar(str[p+2]);
4815  if (n1 < 0 || n2 < 0) {
4816  NCBI_THROW2(CStringException, eFormat,
4817  "Inavild char in extra arg", p);
4818  }
4819  str[dst] = char((n1 << 4) | n2);
4820  p += 3;
4821  break;
4822  }
4823  case '+':
4824  str[dst] = ' ';
4825  p++;
4826  break;
4827  default:
4828  str[dst] = str[p++];
4829  if ( x_IsEncodableChar(str[dst]) ) {
4830  NCBI_THROW2(CStringException, eFormat,
4831  "Unencoded special char in extra arg", p);
4832  }
4833  }
4834  }
4835  if (dst < len) {
4836  str[dst] = '\0';
4837  str.resize(dst);
4838  }
4839  return str;
4840 }
4841 
4842 
4843 bool SDiagMessage::x_ParseExtraArgs(const string& str, size_t pos)
4844 {
4845  m_ExtraArgs.clear();
4846  if (str.find('&', pos) == NPOS && str.find('=', pos) == NPOS) {
4847  return false;
4848  }
4849  CStringPairs<TExtraArgs> parser("&", "=", new CExtraDecoder());
4850  try {
4851  parser.Parse(CTempString(str.c_str() + pos));
4852  }
4853  catch (const CStringException&) {
4854  string n, v;
4855  NStr::SplitInTwo(CTempString(str.c_str() + pos), "=", n, v);
4856  // Try to decode only the name, leave the value as-is.
4857  try {
4858  n = parser.GetDecoder()->Decode(n, CExtraDecoder::eName);
4859  if (n == kExtraTypeArgName) {
4860  m_TypedExtra = true;
4861  }
4862  m_ExtraArgs.push_back(TExtraArg(n, v));
4863  return true;
4864  }
4865  catch (const CStringException&) {
4866  return false;
4867  }
4868  }
4869  ITERATE(TExtraArgs, it, parser.GetPairs()) {
4870  if (it->first == kExtraTypeArgName) {
4871  m_TypedExtra = true;
4872  }
4873  m_ExtraArgs.push_back(TExtraArg(it->first, it->second));
4874  }
4875  return true;
4876 }
4877 
4878 
4879 bool SDiagMessage::ParseMessage(const string& message)
4880 {
4882  m_Buffer = 0;
4883  m_BufferLen = 0;
4884  m_File = 0;
4885  m_Module = 0;
4886  m_Class = 0;
4887  m_Function = 0;
4888  m_Line = 0;
4889  m_ErrCode = 0;
4890  m_ErrSubCode = 0;
4891  m_Flags = 0;
4892  m_Prefix = 0;
4893  m_ErrText = 0;
4894  m_PID = 0;
4895  m_TID = 0;
4896  m_ProcPost = 0;
4897  m_ThrPost = 0;
4898  m_RequestId = 0;
4900  m_TypedExtra = false;
4902  if ( m_Data ) {
4903  delete m_Data;
4904  m_Data = 0;
4905  }
4906  m_Data = new SDiagMessageData;
4907 
4908  size_t pos = 0;
4909  try {
4910  // Fixed prefix
4911  m_PID = s_ParseInt(message, pos, 0, '/');
4912  m_TID = s_ParseInt(message, pos, 0, '/');
4913  size_t sl_pos = message.find('/', pos);
4914  size_t sp_pos = message.find(' ', pos);
4915  if (sl_pos < sp_pos) {
4916  // Newer format, app state is present.
4917  m_RequestId = s_ParseInt(message, pos, 0, '/');
4918  m_Data->m_AppState =
4919  s_StrToAppState(s_ParseStr(message, pos, ' ', true));
4920  }
4921  else {
4922  // Older format, no app state.
4923  m_RequestId = s_ParseInt(message, pos, 0, ' ');
4925  }
4926 
4927  if (message[pos + kDiagW_UID] != ' ') {
4928  return false;
4929  }
4931  CTempString(message.c_str() + pos, kDiagW_UID), 0, 16);
4932  pos += kDiagW_UID + 1;
4933 
4934  m_ProcPost = s_ParseInt(message, pos, 0, '/');
4935  m_ThrPost = s_ParseInt(message, pos, 0, ' ');
4936 
4937  // Date and time. Try all known formats.
4938  CTempString tmp = s_ParseStr(message, pos, ' ');
4939  static const char* s_TimeFormats[4] = {
4940  "Y/M/D:h:m:s", "Y-M-DTh:m:s", "Y-M-DTh:m:s.l", kDiagTimeFormat
4941  };
4942  if (tmp.find('T') == NPOS) {
4943  m_Data->m_Time = CTime(tmp, s_TimeFormats[0]);
4944  }
4945  else if (tmp.find('.') == NPOS) {
4946  m_Data->m_Time = CTime(tmp, s_TimeFormats[1]);
4947  }
4948  else {
4949  try {
4950  m_Data->m_Time = CTime(tmp, s_TimeFormats[2]);
4951  }
4952  catch (const CTimeException&) {
4953  m_Data->m_Time = CTime(tmp, s_TimeFormats[3]);
4954  }
4955  }
4956 
4957  // Host
4958  m_Data->m_Host = s_ParseStr(message, pos, ' ');
4959  if (m_Data->m_Host == kUnknown_Host) {
4960  m_Data->m_Host.clear();
4961  }
4962  // Client
4963  m_Data->m_Client = s_ParseStr(message, pos, ' ');
4964  if (m_Data->m_Client == kUnknown_Client) {
4965  m_Data->m_Client.clear();
4966  }
4967  // Session ID
4968  m_Data->m_Session = s_ParseStr(message, pos, ' ');
4969  if (m_Data->m_Session == kUnknown_Session) {
4970  m_Data->m_Session.clear();
4971  }
4972  // Application name
4973  m_Data->m_AppName = s_ParseStr(message, pos, ' ');
4974  if (m_Data->m_AppName == kUnknown_App) {
4975  m_Data->m_AppName.clear();
4976  }
4977 
4978  // Severity or event type
4979  bool have_severity = false;
4980  size_t severity_pos = pos;
4981  tmp = s_ParseStr(message, pos, ':', true);
4982  if ( !tmp.empty() ) {
4983  // Support both old (LOG_POST -> message) and new (NOTE_POST -> note) styles.
4984  size_t sev_pos = NPOS;
4985  if (tmp.length() == 10 && tmp.find("Message[") == 0) {
4986  sev_pos = 8;
4987  }
4988  else if (tmp.length() == 7 && tmp.find("Note[") == 0) {
4989  sev_pos = 5;
4990  }
4991 
4992  if (sev_pos != NPOS) {
4993  // Get the real severity
4994  switch ( tmp[sev_pos] ) {
4995  case 'T':
4997  break;
4998  case 'I':
5000  break;
5001  case 'W':
5003  break;
5004  case 'E':
5006  break;
5007  case 'C':
5009  break;
5010  case 'F':
5012  break;
5013  default:
5014  return false;
5015  }
5016  m_Flags |= eDPF_IsNote;
5017  have_severity = true;
5018  }
5019  else {
5020  have_severity =
5021  CNcbiDiag::StrToSeverityLevel(string(tmp).c_str(), m_Severity);
5022  }
5023  }
5024  if ( have_severity ) {
5025  pos = message.find_first_not_of(' ', pos);
5026  if (pos == NPOS) {
5027  pos = message.length();
5028  }
5029  }
5030  else {
5031  // Check event type rather than severity level
5032  pos = severity_pos;
5033  tmp = s_ParseStr(message, pos, ' ', true);
5034  if (tmp.empty() && severity_pos < message.length()) {
5035  tmp = CTempString(message.c_str() + severity_pos);
5036  pos = message.length();
5037  }
5038  if (tmp == GetEventName(eEvent_Start)) {
5040  }
5041  else if (tmp == GetEventName(eEvent_Stop)) {
5042  m_Event = eEvent_Stop;
5043  }
5044  else if (tmp == GetEventName(eEvent_RequestStart)) {
5046  if (pos < message.length()) {
5047  if ( x_ParseExtraArgs(message, pos) ) {
5048  pos = message.length();
5049  }
5050  }
5051  }
5052  else if (tmp == GetEventName(eEvent_RequestStop)) {
5054  }
5055  else if (tmp == GetEventName(eEvent_Extra)) {
5057  if (pos < message.length()) {
5058  if ( x_ParseExtraArgs(message, pos) ) {
5059  pos = message.length();
5060  }
5061  }
5062  }
5063  else if (tmp == GetEventName(eEvent_PerfLog)) {
5065  if (pos < message.length()) {
5066  // Put status and time to the message,
5067  // parse all the rest as extra.
5068  size_t msg_end = message.find_first_not_of(' ', pos);
5069  msg_end = message.find_first_of(' ', msg_end);
5070  msg_end = message.find_first_not_of(' ', msg_end);
5071  msg_end = message.find_first_of(' ', msg_end);
5072  size_t extra_pos = message.find_first_not_of(' ', msg_end);
5073  m_Data->m_Message = string(message.c_str() + pos).
5074  substr(0, msg_end - pos);
5075  m_BufferLen = m_Data->m_Message.length();
5076  m_Buffer = m_Data->m_Message.empty() ?
5077  0 : &m_Data->m_Message[0];
5078  if ( x_ParseExtraArgs(message, extra_pos) ) {
5079  pos = message.length();
5080  }
5081  }
5082  }
5083  else {
5084  return false;
5085  }
5086  m_Flags |= eDPF_AppLog;
5087  // The rest is the message (do not parse status, bytes etc.)
5088  if (pos < message.length()) {
5089  m_Data->m_Message = message.c_str() + pos;
5090  m_BufferLen = m_Data->m_Message.length();
5091  m_Buffer = m_Data->m_Message.empty() ?
5092  0 : &m_Data->m_Message[0];
5093  }
5095  return true;
5096  }
5097 
5098  // Find message separator
5099  size_t sep_pos = message.find(" --- ", pos);
5100 
5101  // <module>, <module>(<err_code>.<err_subcode>) or <module>(<err_text>)
5102  if (pos < sep_pos && message[pos] != '"') {
5103  size_t mod_pos = pos;
5104  tmp = s_ParseStr(message, pos, ' ');
5105  size_t lbr = tmp.find("(");
5106  if (lbr != NPOS) {
5107  if (tmp[tmp.length() - 1] != ')') {
5108  // Space(s) inside the error text, try to find closing ')'
5109  int open_br = 1;
5110  while (open_br > 0 && pos < message.length()) {
5111  if (message[pos] == '(') {
5112  open_br++;
5113  }
5114  else if (message[pos] == ')') {
5115  open_br--;
5116  }
5117  pos++;
5118  }
5119  if (message[pos] != ' ' || pos >= message.length()) {
5120  return false;
5121  }
5122  tmp = CTempString(message.c_str() + mod_pos, pos - mod_pos);
5123  // skip space(s)
5124  pos = message.find_first_not_of(' ', pos);
5125  if (pos == NPOS) {
5126  pos = message.length();
5127  }
5128  }
5129  m_Data->m_Module = tmp.substr(0, lbr);
5130  tmp = tmp.substr(lbr + 1, tmp.length() - lbr - 2);
5131  size_t dot_pos = tmp.find('.');
5132  if (dot_pos != NPOS) {
5133  // Try to parse error code/subcode
5134  try {
5135  m_ErrCode = NStr::StringToInt(tmp.substr(0, dot_pos));
5136  m_ErrSubCode = NStr::StringToInt(tmp.substr(dot_pos + 1));
5137  }
5138  catch (const CStringException&) {
5139  m_ErrCode = 0;
5140  m_ErrSubCode = 0;
5141  }
5142  }
5143  if (!m_ErrCode && !m_ErrSubCode) {
5144  m_Data->m_ErrText = tmp;
5145  m_ErrText = m_Data->m_ErrText.empty() ?
5146  0 : m_Data->m_ErrText.c_str();
5147  }
5148  }
5149  else {
5150  m_Data->m_Module = tmp;
5151  }
5152  if ( !m_Data->m_Module.empty() ) {
5153  m_Module = m_Data->m_Module.c_str();
5154  }
5155  }
5156 
5157  if (pos < sep_pos && message[pos] == '"') {
5158  // ["<file>", ][line <line>][:]
5159  pos++; // skip "
5160  tmp = s_ParseStr(message, pos, '"');
5161  m_Data->m_File = tmp;
5162  m_File = m_Data->m_File.empty() ? 0 : m_Data->m_File.c_str();
5163  if (CTempString(message.c_str() + pos, 7) != ", line ") {
5164  return false;
5165  }
5166  pos += 7;
5167  m_Line = (size_t)s_ParseInt(message, pos, 0, ':');
5168  pos = message.find_first_not_of(' ', pos);
5169  if (pos == NPOS) {
5170  pos = message.length();
5171  }
5172  }
5173 
5174  if (pos < sep_pos) {
5175  // Class:: Class::Function() ::Function()
5176  if (message.find("::", pos) != NPOS) {
5177  size_t tmp_pos = sep_pos;
5178  while (tmp_pos > pos && message[tmp_pos - 1] == ' ')
5179  --tmp_pos;
5180  tmp.assign(message.data() + pos, tmp_pos - pos);
5181  size_t dcol = tmp.find("::");
5182  if (dcol == NPOS) {
5183  goto parse_unk_func;
5184  }
5185  pos = sep_pos + 1;
5186  if (dcol > 0) {
5187  m_Data->m_Class = tmp.substr(0, dcol);
5188  m_Class = m_Data->m_Class.empty() ?
5189  0 : m_Data->m_Class.c_str();
5190  }
5191  dcol += 2;
5192  if (dcol < tmp.length() - 2) {
5193  // Remove "()"
5194  if (tmp[tmp.length() - 2] != '(' || tmp[tmp.length() - 1] != ')') {
5195  return false;
5196  }
5197  m_Data->m_Function = tmp.substr(dcol,
5198  tmp.length() - dcol - 2);
5199  m_Function = m_Data->m_Function.empty() ?
5200  0 : m_Data->m_Function.c_str();
5201  }
5202  }
5203  else {
5204 parse_unk_func:
5205  size_t unkf = message.find("UNK_FUNC", pos);
5206  if (unkf == pos) {
5207  pos += 9;
5208  }
5209  }
5210  }
5211 
5212  if (CTempString(message.c_str() + pos, 4) == "--- ") {
5213  pos += 4;
5214  }
5215 
5216  // All the rest goes to message - no way to parse prefix/error code.
5217  // [<prefix1>::<prefix2>::.....]
5218  // <message>
5219  // <err_code_message> and <err_code_explanation>
5220  m_Data->m_Message = message.c_str() + pos;
5221  m_BufferLen = m_Data->m_Message.length();
5222  m_Buffer = m_Data->m_Message.empty() ? 0 : &m_Data->m_Message[0];
5223  }
5224  catch (const CException&) {
5225  return false;
5226  }
5227 
5229  return true;
5230 }
5231 
5232 
5234  INextDiagMessage& func)
5235 {
5236  string msg_str, line, last_msg_str;
5237  bool res = false;
5238  unique_ptr<SDiagMessage> msg;
5239  unique_ptr<SDiagMessage> last_msg;
5240  while ( in.good() ) {
5241  getline(in, line);
5242  // Dirty check for PID/TID/RID
5243  if (line.size() < 15) {
5244  if ( !line.empty() ) {
5245  msg_str += "\n" + line;
5246  line.erase();
5247  }
5248  continue;
5249  }
5250  else {
5251  for (size_t i = 0; i < 15; i++) {
5252  if (line[i] != '/' && (line[i] < '0' || line[i] > '9')) {
5253  // Not a valid prefix - append to the previous message
5254  msg_str += "\n" + line;
5255  line.erase();
5256  break;
5257  }
5258  }
5259  if ( line.empty() ) {
5260  continue;
5261  }
5262  }
5263  if ( msg_str.empty() ) {
5264  msg_str = line;
5265  continue;
5266  }
5267  msg.reset(new SDiagMessage(msg_str, &res));
5268  if ( res ) {
5269  if ( last_msg.get() ) {
5270  func(*last_msg);
5271  }
5272  last_msg_str = msg_str;
5273  last_msg.reset(msg.release());
5274  }
5275  else if ( !last_msg_str.empty() ) {
5276  last_msg_str += "\n" + msg_str;
5277  last_msg.reset(new SDiagMessage(last_msg_str, &res));
5278  if ( !res ) {
5279  ERR_POST_X(19,
5280  Error << "Failed to parse message: " << last_msg_str);
5281  }
5282  }
5283  else {
5284  ERR_POST_X(20, Error << "Failed to parse message: " << msg_str);
5285  }
5286  msg_str = line;
5287  }
5288  if ( !msg_str.empty() ) {
5289  msg.reset(new SDiagMessage(msg_str, &res));
5290  if ( res ) {
5291  if ( last_msg.get() ) {
5292  func(*last_msg);
5293  }
5294  func(*msg);
5295  }
5296  else if ( !last_msg_str.empty() ) {
5297  last_msg_str += "\n" + msg_str;
5298  msg.reset(new SDiagMessage(last_msg_str, &res));
5299  if ( res ) {
5300  func(*msg);
5301  }
5302  else {
5303  ERR_POST_X(21,
5304  Error << "Failed to parse message: " << last_msg_str);
5305  }
5306  }
5307  else {
5308  ERR_POST_X(22,
5309  Error << "Failed to parse message: " << msg_str);
5310  }
5311  }
5312 }
5313 
5314 
5316 {
5317  switch ( event ) {
5318  case eEvent_Start:
5319  return "start";
5320  case eEvent_Stop:
5321  return "stop";
5322  case eEvent_Extra:
5323  return "extra";
5324  case eEvent_RequestStart:
5325  return "request-start";
5326  case eEvent_RequestStop:
5327  return "request-stop";
5328  case eEvent_PerfLog:
5329  return "perf";
5330  }
5331  return kEmptyStr;
5332 }
5333 
5334 
5336 {
5337  return m_Data ? m_Data->m_UID : GetDiagContext().GetUID();
5338 }
5339 
5340 
5342 {
5343  return m_Data ? m_Data->m_Time : s_GetFastTime();
5344 }
5345 
5346 
5347 inline
5349 {
5351  : m_Format == eFormat_Old;
5352 }
5353 
5354 
5356 {
5357  stringstream ostr;
5358  Write(ostr, flags);
5359  str = ostr.str();
5360 }
5361 
5362 
5364  TDiagWriteFlags flags) const
5365 {
5366  CNcbiOstream& res =
5368 
5369  return res;
5370 }
5371 
5372 
5373 string SDiagMessage::x_GetModule(void) const
5374 {
5375  if ( m_Module && *m_Module ) {
5376  return string(m_Module);
5377  }
5378  if ( x_IsSetOldFormat() ) {
5379  return kEmptyStr;
5380  }
5381  if ( !m_File || !(*m_File) ) {
5382  return kEmptyStr;
5383  }
5384  char sep_chr = CDirEntry::GetPathSeparator();
5385  const char* mod_start = 0;
5386  const char* mod_end = m_File;
5387  const char* c = strchr(m_File, sep_chr);
5388  while (c && *c) {
5389  if (c > mod_end) {
5390  mod_start = mod_end;
5391  mod_end = c;
5392  }
5393  c = strchr(c + 1, sep_chr);
5394  }
5395  if ( !mod_start ) {
5396  mod_start = m_File;
5397  }
5398  while (*mod_start == sep_chr) {
5399  mod_start++;
5400  }
5401  if (mod_end < mod_start + 1) {
5402  return kEmptyStr;
5403  }
5404  string ret(mod_start, mod_end - mod_start);
5405  NStr::ToUpper(ret);
5406  return ret;
5407 }
5408 
5409 
5411 {
5412 public:
5413  CExtraEncoder(bool allow_bad_names = false) : m_AllowBadNames(allow_bad_names) {}
5414 
5415  virtual string Encode(const CTempString src, EStringType stype) const;
5416 
5417 private:
5419 };
5420 
5421 
5422 string CExtraEncoder::Encode(const CTempString src, EStringType stype) const
5423 {
5424  static const char* s_BadSymbolPrefix = "[INVALID_APPLOG_SYMBOL:";
5425  static const char* s_BadSymbolSuffix = "]";
5426  static const size_t s_BadSymbolPrefixLen = strlen(s_BadSymbolPrefix);
5427  static const CTempString s_EncodedSpace = "%20";
5428 
5429  vector<CTempString> parts;
5430  parts.resize(src.length() + 2); // adjust for possible invalid symbol message
5431  size_t part_idx = 0;
5432  const char* src_data = src.data();
5433  const bool warn_bad_name = (stype == eName && !m_AllowBadNames);
5434  size_t good_start = 0;
5435  size_t total_len = 0;
5436  for (size_t pos = 0; pos < src.size(); ++pos) {
5437  char c = src[pos];
5438  const char* enc = s_ExtraEncodeChars[(unsigned char)c];
5439  if (enc[0] == c && enc[1] == 0) continue;
5440 
5441  // Save good chars, if any.
5442  if (good_start < pos) {
5443  CTempString& good_part = parts[part_idx++];
5444  good_part.assign(src_data + good_start, pos - good_start);
5445  total_len += good_part.size();
5446  }
5447 
5448  if (warn_bad_name) {
5449  CTempString& warn_part = parts[part_idx++];
5450  warn_part.assign(s_BadSymbolPrefix, s_BadSymbolPrefixLen);
5451  total_len += s_BadSymbolPrefixLen;
5452  }
5453  CTempString& enc_part = parts[part_idx++];
5454  enc_part.assign((c == ' ' && warn_bad_name) ? s_EncodedSpace : enc);
5455  total_len += enc_part.size();
5456  if (warn_bad_name) {
5457  CTempString& warn2_part = parts[part_idx++];
5458  warn2_part.assign(s_BadSymbolSuffix, 1);
5459  total_len++;
5460  }
5461  good_start = pos + 1;
5462 
5463  if (part_idx + 3 >= parts.size()) parts.resize(parts.size() * 2);
5464  }
5465 
5466  if (good_start < src.size()) {
5467  CTempString& good_part = parts[part_idx++];
5468  good_part.assign(src_data + good_start, src.size() - good_start);
5469  total_len += good_part.size();
5470  }
5471 
5472  char* buf = new char[total_len];
5473  char* pos = buf;
5474  for (size_t i = 0; i < part_idx; ++i) {
5475  const CTempString& part = parts[i];
5476  strncpy(pos, part.data(), part.size());
5477  pos += part.size();
5478  }
5479  string ret(buf, total_len);
5480  delete[] buf;
5481  return ret;
5482 }
5483 
5484 
5486 {
5488  "&", "=", new CExtraEncoder(m_AllowBadExtraNames));
5489 }
5490 
5491 
5492 // Merge lines in-place:
5493 // \n -> \v
5494 // \v -> 0xFF + \v
5495 // 0xFF -> 0xFF 0xFF
5497 {
5498  size_t p = buf.find_first_of("\n\v\377");
5499  if (p == NPOS) return;
5500  for (; p < buf.size(); p++) {
5501  switch (buf[p]) {
5502  case '\377':
5503  case '\v':
5504  buf.insert(p, 1, '\377');
5505  p++;
5506  break;
5507  case '\n':
5508  buf[p] = '\v';
5509  break;
5510  }
5511  }
5512 }
5513 
5514 
5516 {
5517  if (buf.find_first_of("\v\377") == NPOS) return;
5518  size_t src = 0, dst = 0;
5519  for (; src < buf.size(); src++, dst++) {
5520  switch (buf[src]) {
5521  case '\377':
5522  if (src < buf.size() - 1 &&
5523  (buf[src + 1] == '\377' || buf[src + 1] == '\v')) {
5524  src++; // skip escape char
5525  }
5526  break;
5527  case '\v':
5528  // non-escaped VT
5529  buf[dst] = '\n';
5530  continue;
5531  }
5532  if (dst != src) {
5533  buf[dst] = buf[src];
5534  }
5535  }
5536  buf.resize(dst);
5537 }
5538 
5539 
5541  eDiagMergeLines_Default, // Do not force line merging
5542  eDiagMergeLines_Off, // Force line breaks
5543  eDiagMergeLines_On // Escape line breaks
5544 };
5545 
5546 
5549 {
5550  {"Default", eDiagMergeLines_Default},
5551  {"Off", eDiagMergeLines_Off},
5552  {"On", eDiagMergeLines_On}
5553 };
5554 
5557  eParam_NoThread, DIAG_MERGE_LINES);
5558 
5559 
5560 // Formatted output of stack trace
5562 {
5563  string old_prefix = trace.GetPrefix();
5564  trace.SetPrefix(" ");
5565  os << "\n Stack trace:\n" << trace;
5566  trace.SetPrefix(old_prefix);
5567 }
5568 
5569 
5571  TDiagWriteFlags flags) const
5572 {
5573  // Temp stream - the result will be passed to line merging.
5574  // Error text, module, prefix etc. can have linebreaks which need to
5575  // be escaped.
5576  stringstream os;
5577 
5578  // Date & time
5580  os << CFastLocalTime().GetLocalTime().AsString("M/D/y h:m:s ");
5581  }
5582 #ifdef NCBI_THREADS
5584  os << 'T' << CThread::GetSelf() << ' ';
5585  }
5586 #endif
5587  // "<file>"
5588  bool print_file = (m_File && *m_File &&
5590  if ( print_file ) {
5591  const char* x_file = m_File;
5593  for (const char* s = m_File; *s; s++) {
5594  if (*s == '/' || *s == '\\' || *s == ':')
5595  x_file = s + 1;
5596  }
5597  }
5598  os << '"' << x_file << '"';
5599  }
5600 
5601  // , line <line>
5602  bool print_line = (m_Line && IsSetDiagPostFlag(eDPF_Line, m_Flags));
5603  if ( print_line )
5604  os << (print_file ? ", line " : "line ") << m_Line;
5605 
5606  // :
5607  if (print_file || print_line)
5608  os << ": ";
5609 
5610  // Get error code description
5611  bool have_description = false;
5612  SDiagErrCodeDescription description;
5613  if ((m_ErrCode || m_ErrSubCode) &&
5618 
5620  if ( info &&
5621  info->GetDescription(ErrCode(m_ErrCode, m_ErrSubCode),
5622  &description) ) {
5623  have_description = true;
5625  description.m_Severity != -1 )
5626  m_Severity = (EDiagSev)description.m_Severity;
5627  }
5628  }
5629 
5630  // <severity>:
5633  string sev = CNcbiDiag::SeverityName(m_Severity);
5635  os << "Note[" << sev[0] << "]";
5636  }
5637  else {
5638  os << sev;
5639  }
5640  os << ": ";
5641  }
5642 
5643  // (<err_code>.<err_subcode>) or (err_text)
5644  if ((m_ErrCode || m_ErrSubCode || m_ErrText) &&
5646  os << '(';
5647  if (m_ErrText) {
5648  os << m_ErrText;
5649  } else {
5650  os << m_ErrCode << '.' << m_ErrSubCode;
5651  }
5652  os << ") ";
5653  }
5654 
5655  // Module::Class::Function -
5656  bool have_module = (m_Module && *m_Module);
5657  bool print_location =
5658  ( have_module ||
5659  (m_Class && *m_Class ) ||
5660  (m_Function && *m_Function))
5662 
5663  bool need_separator = false;
5664  if (print_location) {
5665  // Module:: Module::Class Module::Class::Function()
5666  // ::Class ::Class::Function()
5667  // Module::Function() Function()
5668  bool need_double_colon = false;
5669 
5670  if ( have_module ) {
5671  os << x_GetModule();
5672  need_double_colon = true;
5673  }
5674 
5675  if (m_Class && *m_Class) {
5676  if (need_double_colon)
5677  os << "::";
5678  os << m_Class;
5679  need_double_colon = true;
5680  }
5681 
5682  if (m_Function && *m_Function) {
5683  if (need_double_colon)
5684  os << "::";
5685  need_double_colon = false;
5686  os << m_Function << "()";
5687  }
5688 
5689  if( need_double_colon )
5690  os << "::";
5691 
5692  os << " ";
5693  need_separator = true;
5694  }
5695 
5696  bool err_text_prefix = (IsSetDiagPostFlag(eDPF_ErrCodeMsgInFront));
5697  if (err_text_prefix && have_description &&
5699  !description.m_Message.empty()) {
5700  os << "{" << description.m_Message << "} ";
5701  need_separator = true;
5702  }
5703 
5704  if (need_separator) {
5705  os << "- ";
5706  }
5707 
5708  // [<prefix1>::<prefix2>::.....]
5710  os << '[' << m_Prefix << "] ";
5711 
5712  // <message>
5713  if (m_BufferLen)
5714  os.write(m_Buffer, m_BufferLen);
5715 
5716  // <err_code_message> and <err_code_explanation>
5717  if (have_description) {
5718  if (!err_text_prefix &&
5720  !description.m_Message.empty())
5721  os << NcbiEndl << description.m_Message;
5723  !description.m_Explanation.empty())
5724  os << NcbiEndl << description.m_Explanation;
5725  }
5726 
5727  if ( m_PrintStackTrace ) {
5729  }
5730 
5731  string buf = os.str();
5732  bool merge_lines = IsSetDiagPostFlag(eDPF_MergeLines, m_Flags);
5733  static CSafeStatic<NCBI_PARAM_TYPE(Diag, Merge_Lines)> s_DiagMergeLines;
5734  switch (s_DiagMergeLines->Get()) {
5735  case eDiagMergeLines_On:
5736  merge_lines = true;
5737  break;
5738  case eDiagMergeLines_Off:
5739  merge_lines = false;
5740  break;
5741  default:
5742  break;
5743  }
5744  if (merge_lines) {
5745  NStr::ReplaceInPlace(buf, "\n", ";");
5746  }
5747  out_str << buf;
5748 
5749  // Endl
5750  if ((flags & fNoEndl) == 0) {
5751  out_str << NcbiEndl;
5752  }
5753 
5754  return out_str;
5755 }
5756 
5757 
5759  TDiagWriteFlags flags) const
5760 {
5761  // Temp stream - the result will be passed to line merging.
5762  // Error text, module, prefix etc. can have linebreaks which need to
5763  // be escaped.
5764  stringstream os;
5765 
5766  if ((flags & fNoPrefix) == 0) {
5767  GetDiagContext().WriteStdPrefix(os, *this);
5768  }
5769 
5770  // Get error code description
5771  bool have_description = false;
5772  SDiagErrCodeDescription description;
5773  if ((m_ErrCode || m_ErrSubCode) &&
5776 
5778  if ( info &&
5779  info->GetDescription(ErrCode(m_ErrCode, m_ErrSubCode),
5780  &description) ) {
5781  have_description = true;
5782  if (description.m_Severity != -1)
5783  m_Severity = (EDiagSev)description.m_Severity;
5784  }
5785  }
5786 
5787  // <severity>:
5789  os << setfill(' ') << setw(13) << setiosflags(IOS_BASE::left)
5790  << GetEventName(m_Event) << resetiosflags(IOS_BASE::left)
5791  << setw(0);
5792  }
5793  else {
5794  string sev = CNcbiDiag::SeverityName(m_Severity);
5795  os << setfill(' ') << setw(13) // add 1 for space
5796  << setiosflags(IOS_BASE::left) << setw(0);
5798  os << "Note[" << sev[0] << "]:";
5799  }
5800  else {
5801  os << sev << ':';
5802  }
5803  os << resetiosflags(IOS_BASE::left);
5804  }
5805  os << ' ';
5806 
5807  // <module>-<err_code>.<err_subcode> or <module>-<err_text>
5808  bool have_module = (m_Module && *m_Module) || (m_File && *m_File);
5809  bool print_err_id = have_module || m_ErrCode || m_ErrSubCode || m_ErrText;
5810 
5811  if (print_err_id) {
5812  os << (have_module ? x_GetModule() : "UNK_MODULE");
5813  if (m_ErrCode || m_ErrSubCode || m_ErrText) {
5814  if (m_ErrText) {
5815  os << '(' << m_ErrText << ')';
5816  } else {
5817  os << '(' << m_ErrCode << '.' << m_ErrSubCode << ')';
5818  }
5819  }
5820  os << ' ';
5821  }
5822 
5823  // "<file>"
5825  bool print_file = m_File && *m_File;
5826  if ( print_file ) {
5827  const char* x_file = m_File;
5829  for (const char* s = m_File; *s; s++) {
5830  if (*s == '/' || *s == '\\' || *s == ':')
5831  x_file = s + 1;
5832  }
5833  }
5834  os << '"' << x_file << '"';
5835  }
5836  else {
5837  os << "\"UNK_FILE\"";
5838  }
5839  // , line <line>
5840  os << ", line " << m_Line;
5841  os << ": ";
5842 
5843  // Class::Function
5844  bool print_loc = (m_Class && *m_Class ) || (m_Function && *m_Function);
5845  if (print_loc) {
5846  // Class:: Class::Function() ::Function()
5847  if (m_Class && *m_Class) {
5848  os << m_Class;
5849  }
5850  os << "::";
5851  if (m_Function && *m_Function) {
5852  os << m_Function << "() ";
5853  }
5854  }
5855  else {
5856  os << "UNK_FUNC ";
5857  }
5858 
5861  os << "--- ";
5862  }
5863  }
5864 
5865  // [<prefix1>::<prefix2>::.....]
5867  os << '[' << m_Prefix << "] ";
5868 
5869  // <message>
5870  if (m_BufferLen) {
5871  os.write(m_Buffer, m_BufferLen);
5872  }
5873 
5875  if ( !m_ExtraArgs.empty() ) {
5876  if ( m_BufferLen ) {
5877  os << ' ';
5878  }
5879  os << FormatExtraMessage();
5880  }
5881  }
5882 
5883  // <err_code_message> and <err_code_explanation>
5884  if (have_description) {
5886  !description.m_Message.empty())
5887  os << '\n' << description.m_Message << ' ';
5889  !description.m_Explanation.empty())
5890  os << '\n' << description.m_Explanation;
5891  }
5892 
5893  if ( m_PrintStackTrace ) {
5895  }
5896 
5897  string buf = os.str();
5898  // Line merging in new (applog) format is unconditional.
5900  auto max_len = s_MaxLineLength->Get();
5901  if (max_len > 0 && buf.size() > max_len) {
5902  buf.resize(max_len);
5903  }
5904  out_str << buf;
5905 
5906  // Endl
5907  if ((flags & fNoEndl) == 0) {
5908  // In applog format always use \n only. The stream must be in binary mode.
5909  out_str << '\n';
5910  }
5911  return out_str;
5912 }
5913 
5914 
5916 {
5917  if ( !m_Data ) {
5918  m_Data = new SDiagMessageData;
5919  }
5920  if (m_Data->m_Message.empty() && m_Buffer) {
5922  }
5923  if (m_Data->m_File.empty() && m_File) {
5924  m_Data->m_File = m_File;
5925  }
5926  if (m_Data->m_Module.empty() && m_Module) {
5928  }
5929  if (m_Data->m_Class.empty() && m_Class) {
5930  m_Data->m_Class = m_Class;
5931  }
5932  if (m_Data->m_Function.empty() && m_Function) {
5934  }
5935  if (m_Data->m_Prefix.empty() && m_Prefix) {
5937  }
5938  if (m_Data->m_ErrText.empty() && m_ErrText) {
5940  }
5941 
5942  if ( !m_Data->m_UID ) {
5944  }
5945  if ( m_Data->m_Time.IsEmpty() ) {
5947  }
5948 }
5949 
5950 
5952 {
5953  if ( m_Data ) {
5954  return;
5955  }
5956  x_InitData();
5957  CDiagContext& dctx = GetDiagContext();
5958  m_Data->m_Host = dctx.GetEncodedHost();
5960  m_Data->m_AppState = dctx.GetAppState();
5961 
5962  CRequestContext& rctx = dctx.GetRequestContext();
5963  m_Data->m_Client = rctx.GetClientIP();
5965 }
5966 
5967 
5968 const string& SDiagMessage::GetHost(void) const
5969 {
5970  if ( m_Data ) {
5971  return m_Data->m_Host;
5972  }
5973  return GetDiagContext().GetEncodedHost();
5974 }
5975 
5976 
5977 string SDiagMessage::GetClient(void) const
5978 {
5979  return m_Data ? m_Data->m_Client
5981 }
5982 
5983 
5984 string SDiagMessage::GetSession(void) const
5985 {
5986  return m_Data ? m_Data->m_Session
5988 }
5989 
5990 
5991 const string& SDiagMessage::GetAppName(void) const
5992 {
5993  if ( m_Data ) {
5994  return m_Data->m_AppName;
5995  }
5996  return GetDiagContext().GetEncodedAppName();
5997 }
5998 
5999 
6001 {
6003 }
6004 
6005 
6006 ///////////////////////////////////////////////////////
6007 // CDiagAutoPrefix::
6008 
6010 {
6011  PushDiagPostPrefix(prefix.c_str());
6012 }
6013 
6015 {
6017 }
6018 
6020 {
6022 }
6023 
6024 
6025 ///////////////////////////////////////////////////////
6026 // EXTERN
6027 
6028 
6030  TDiagPostFlags new_flags)
6031 {
6033 
6034  TDiagPostFlags prev_flags = flags;
6035  new_flags &= ~eDPF_AtomicWrite;
6036  if (new_flags & eDPF_Default) {
6037  new_flags |= prev_flags;
6038  new_flags &= ~eDPF_Default;
6039  }
6040  flags = new_flags;
6041  return prev_flags;
6042 }
6043 
6044 
6046 {
6047  if (flag == eDPF_Default)
6048  return;
6049 
6051  flags |= flag;
6052 }
6053 
6054 
6056 {
6057  if (flag == eDPF_Default)
6058  return;
6059 
6061  flags &= ~flag;
6062 }
6063 
6064 
6066 {
6067  return s_SetDiagPostAllFlags(CDiagBuffer::sx_GetPostFlags(), flags);
6068 }
6069 
6071 {
6072  s_SetDiagPostFlag(CDiagBuffer::sx_GetPostFlags(), flag);
6073 }
6074 
6076 {
6077  s_UnsetDiagPostFlag(CDiagBuffer::sx_GetPostFlags(), flag);
6078 }
6079 
6080 
6082 {
6083  return s_SetDiagPostAllFlags(CDiagBuffer::sm_TraceFlags, flags);
6084 }
6085 
6087 {
6088  s_SetDiagPostFlag(CDiagBuffer::sm_TraceFlags, flag);
6089 }
6090 
6092 {
6093  s_UnsetDiagPostFlag(CDiagBuffer::sm_TraceFlags, flag);
6094 }
6095 
6096 
6097 extern void SetDiagPostPrefix(const char* prefix)
6098 {
6099  CDiagBuffer& buf = GetDiagBuffer();
6100  if ( prefix ) {
6101  buf.m_PostPrefix = prefix;
6102  } else {
6103  buf.m_PostPrefix.erase();
6104  }
6105  buf.m_PrefixList.clear();
6106 }
6107 
6108 
6109 extern void PushDiagPostPrefix(const char* prefix)
6110 {
6111  if (prefix && *prefix) {
6112  CDiagBuffer& buf = GetDiagBuffer();
6113  buf.m_PrefixList.push_back(prefix);
6114  buf.UpdatePrefix();
6115  }
6116 }
6117 
6118 
6119 extern void PopDiagPostPrefix(void)
6120 {
6121  CDiagBuffer& buf = GetDiagBuffer();
6122  if ( !buf.m_PrefixList.empty() ) {
6123  buf.m_PrefixList.pop_back();
6124  buf.UpdatePrefix();
6125  }
6126 }
6127 
6128 
6130 {
6131  if (post_sev < eDiagSevMin || post_sev > eDiagSevMax) {
6132  NCBI_THROW(CCoreException, eInvalidArg,
6133  "SetDiagPostLevel() -- Severity must be in the range "
6134  "[eDiagSevMin..eDiagSevMax]");
6135  }
6136 
6138  EDiagSev sev = CDiagBuffer::sm_PostSeverity;
6139  if ( CDiagBuffer::sm_PostSeverityChange != eDiagSC_Disable) {
6140  if (post_sev == eDiag_Trace) {
6141  // special case
6143  post_sev = eDiag_Info;
6144  }
6145  CDiagBuffer::sm_PostSeverity = post_sev;
6146  }
6147  return sev;
6148 }
6149 
6150 
6152 {
6153  return CDiagBuffer::sm_PostSeverity;
6154 }
6155 
6156 
6158 {
6159  if (sev1 == sev2) return 0;
6160  if (sev1 == eDiag_Trace) return -1;
6161  if (sev2 == eDiag_Trace) return 1;
6162  return sev1 - sev2;
6163 }
6164 
6165 
6167 {
6168  if (sev == eDiag_Trace) {
6169  return CDiagBuffer::GetTraceEnabled();
6170  }
6171  EDiagSev sev2;
6172  {{
6173  sev2 = AdjustApplogPrintableSeverity(CDiagBuffer::sm_PostSeverity);
6174  }}
6175  return CompareDiagPostLevel(sev, sev2) >= 0;
6176 }
6177 
6178 
6179 extern void SetDiagFixedPostLevel(const EDiagSev post_sev)
6180 {
6181  SetDiagPostLevel(post_sev);
6183 }
6184 
6185 
6186 extern bool DisableDiagPostLevelChange(bool disable_change)
6187 {
6189  bool prev_status = (CDiagBuffer::sm_PostSeverityChange == eDiagSC_Enable);
6190  CDiagBuffer::sm_PostSeverityChange = disable_change ? eDiagSC_Disable :
6192  return prev_status;
6193 }
6194 
6195 
6197 {
6198  if (die_sev < eDiagSevMin || die_sev > eDiag_Fatal) {
6199  NCBI_THROW(CCoreException, eInvalidArg,
6200  "SetDiagDieLevel() -- Severity must be in the range "
6201  "[eDiagSevMin..eDiag_Fatal]");
6202  }
6203 
6205  EDiagSev sev = CDiagBuffer::sm_DieSeverity;
6206  CDiagBuffer::sm_DieSeverity = die_sev;
6207  return sev;
6208 }
6209 
6210 
6212 {
6213  return CDiagBuffer::sm_DieSeverity;
6214 }
6215 
6216 
6217 extern bool IgnoreDiagDieLevel(bool ignore)
6218 {
6220  bool retval = CDiagBuffer::sm_IgnoreToDie;
6221  CDiagBuffer::sm_IgnoreToDie = ignore;
6222  return retval;
6223 }
6224 
6225 
6226 extern void SetDiagTrace(EDiagTrace how, EDiagTrace dflt)
6227 {
6229  (void) CDiagBuffer::GetTraceEnabled();
6230 
6231  if (dflt != eDT_Default)
6232  CDiagBuffer::sm_TraceDefault = dflt;
6233 
6234  if (how == eDT_Default)
6235  how = CDiagBuffer::sm_TraceDefault;
6236  CDiagBuffer::sm_TraceEnabled = (how == eDT_Enable);
6237 }
6238 
6239 
6240 extern bool GetDiagTrace(void)
6241 {
6242  return CDiagBuffer::GetTraceEnabled();
6243 }
6244 
6245 
6247  : m_MinSev(NCBI_PARAM_TYPE(Diag, Tee_Min_Severity)::GetDefault()),
6248  m_OrigHandler(orig, own_orig ? eTakeOwnership : eNoOwnership)
6249 {
6250  // Prevent recursion
6251  CTeeDiagHandler* tee = dynamic_cast<CTeeDiagHandler*>(m_OrigHandler.get());
6252  if ( tee ) {
6254  }
6256  if (str && str->GetLogName() == kLogName_Stderr) {
6257  m_OrigHandler.reset();
6258  }
6259 }
6260 
6261 
6263 {
6264  if ( m_OrigHandler.get() ) {
6265  m_OrigHandler->Post(mess);
6266  }
6267 
6268  if ( mess.m_NoTee ) {
6269  // The message has been printed.
6270  return;
6271  }
6272 
6273  // Ignore posts below the min severity and applog messages
6274  if ((mess.m_Flags & eDPF_AppLog) ||
6276  return;
6277  }
6278 
6279  stringstream str_os;
6280  mess.x_OldWrite(str_os);
6282  string str = str_os.str();
6283  cerr.write(str.data(), str.size());
6284  cerr << NcbiFlush;
6285 }
6286 
6287 
6288 extern void SetDiagHandler(CDiagHandler* handler, bool can_delete)
6289 {
6292  bool report_switch = ctx.IsSetOldPostFormat() &&
6294  string old_name, new_name;
6295 
6296  if ( CDiagBuffer::sm_Handler ) {
6297  old_name = CDiagBuffer::sm_Handler->GetLogName();
6298  }
6299  if ( handler ) {
6300  new_name = handler->GetLogName();
6301  if (report_switch && new_name != old_name) {
6302  ctx.Extra().Print("switch_diag_to", new_name);
6303  }
6304  }
6305  // Do not delete old handler if it's reinstalled (possibly just to change
6306  // the ownership).
6307  if (CDiagBuffer::sm_CanDeleteHandler && CDiagBuffer::sm_Handler != handler)
6308  delete CDiagBuffer::sm_Handler;
6309  if ( TTeeToStderr::GetDefault() ) {
6310  // Need to tee?
6311  handler = new CTeeDiagHandler(handler, can_delete);
6312  can_delete = true;
6313  }
6314  CDiagBuffer::sm_Handler = handler;
6315  CDiagBuffer::sm_CanDeleteHandler = can_delete;
6316  if (report_switch && !old_name.empty() && new_name != old_name) {
6317  ctx.Extra().Print("switch_diag_from", old_name);
6318  }
6319  // Unlock severity
6321 }
6322 
6323 
6324 extern bool IsSetDiagHandler(void)
6325 {
6326  return (CDiagBuffer::sm_Handler != s_DefaultHandler);
6327 }
6328 
6329 extern CDiagHandler* GetDiagHandler(bool take_ownership,
6330  bool* current_ownership)
6331 {
6333  if ( current_ownership ) {
6334  *current_ownership = CDiagBuffer::sm_CanDeleteHandler;
6335  }
6336  if (take_ownership) {
6337  _ASSERT(CDiagBuffer::sm_CanDeleteHandler);
6338  CDiagBuffer::sm_CanDeleteHandler = false;
6339  }
6340  return CDiagBuffer::sm_Handler;
6341 }
6342 
6343 
6344 extern void DiagHandler_Reopen(void)
6345 {
6347  if ( handler ) {
6348  handler->Reopen(CDiagHandler::fCheck);
6349  }
6350 }
6351 
6352 
6353 extern CDiagBuffer& GetDiagBuffer(void)
6354 {
6356 }
6357 
6358 
6360 {
6361  if (GetLogName() == kLogName_Stderr &&
6363  // Already posted to console.
6364  return;
6365  }
6367  stringstream str_os;
6368  str_os << mess;
6369  string str = str_os.str();
6370  cerr.write(str.data(), str.size());
6371  cerr << NcbiFlush;
6372 }
6373 
6374 
6376 {
6377  string name = typeid(*this).name();
6378  return name.empty() ? kLogName_Unknown
6379  : string(kLogName_Unknown) + "(" + name + ")";
6380 }
6381 
6382 
6384 {
6385  return false;
6386 }
6387 
6388 
6390 {
6391  _ASSERT(0);
6392  return kEmptyStr;
6393 }
6394 
6395 
6396 void CDiagHandler::WriteMessage(const char*, size_t, EDiagFileType)
6397 {
6398  _ASSERT(0);
6399 }
6400 
6401 
6403 {
6405 }
6406 
6407 
6409 {
6410  return m_LogName;
6411 }
6412 
6413 
6414 void CStreamDiagHandler_Base::SetLogName(const string& log_name)
6415 {
6416  size_t len = min(log_name.length(), sizeof(m_LogName) - 1);
6417  memcpy(m_LogName, log_name.data(), len);
6418  m_LogName[len] = '\0';
6419 }
6420 
6421 
6423  bool quick_flush,
6424  const string& stream_name)
6425  : m_Stream(os),
6426  m_QuickFlush(quick_flush)
6427 {
6428  if ( !stream_name.empty() ) {
6429  SetLogName(stream_name);
6430  }
6431 }
6432 
6433 
6435 {
6436  if ( !m_Stream ) {
6437  return;
6438  }
6440  if (m_Stream->bad()) return;
6441  m_Stream->clear();
6442  stringstream str_os;
6443  str_os << mess;
6444  string str = str_os.str();
6445  m_Stream->write(str.data(), str.size());
6446  if (!m_Stream->good()) return;
6447  if (m_QuickFlush) {
6448  *m_Stream << NcbiFlush;
6449  }
6450 }
6451 
6452 
6455  : m_Handle(-1)
6456 {
6457 #if defined(NCBI_OS_MSWIN)
6458  int mode = O_WRONLY | O_APPEND | O_CREAT | O_BINARY | O_NOINHERIT;
6459 #else
6460  int mode = O_WRONLY | O_APPEND | O_CREAT;
6461 #endif
6462 
6464  mode |= O_TRUNC;
6465  }
6466 
6471  0);
6474  mode, perm);
6475 #if defined(NCBI_OS_UNIX)
6476  fcntl(m_Handle, F_SETFD, fcntl(m_Handle, F_GETFD, 0) | FD_CLOEXEC);
6477 #endif
6478 }
6479 
6481 {
6482  if (m_Handle >= 0) {
6484  }
6485 }
6486 
6487 
6488 // CFileDiagHandler
6489 
6491  : m_FileType(file_type),
6492  m_HavePosts(false),
6493  m_LowDiskSpace(false),
6494  m_Handle(NULL),
6495  m_HandleLock(new CSpinLock()),
6496  m_ReopenTimer(new CStopWatch())
6497 {
6498  SetLogName(fname);
6500 }
6501 
6502 
6504 {
6505  delete m_ReopenTimer;
6506  delete m_HandleLock;
6507  if (m_Handle)
6509 }
6510 
6511 
6512 void CFileHandleDiagHandler::SetLogName(const string& log_name)
6513 {
6514  string abs_name = CDirEntry::IsAbsolutePath(log_name) ? log_name
6515  : CDirEntry::CreateAbsolutePath(log_name);
6516  TParent::SetLogName(abs_name);
6517 }
6518 
6519 
6520 const int kLogReopenDelay = 60; // Reopen log every 60 seconds
6521 
6523 {
6524  s_ReopenEntered->Add(1);
6526  if (m_FileType == eDiagFile_Perf && !m_HavePosts) {
6527  s_ReopenEntered->Add(-1);
6528  return;
6529  }
6530  // Period is longer than for CFileDiagHandler to prevent double-reopening
6531  if (flags & fCheck && m_ReopenTimer->IsRunning()) {
6532  if (m_ReopenTimer->Elapsed() < kLogReopenDelay + 5) {
6533  s_ReopenEntered->Add(-1);
6534  return;
6535  }
6536  }
6537 
6538  if (m_Handle) {
6539  // This feature of automatic log rotation will work correctly only on
6540  // Unix with only one CFileHandleDiagHandler for each physical file.
6541  // This is how it was requested to work by Denis Vakatov.
6542  long pos = NcbiSys_lseek(m_Handle->GetHandle(), 0, SEEK_CUR);
6543  long limit = s_LogSizeLimit->Get();
6544  if (limit > 0 && pos > limit) {
6545  CFile f(GetLogName());
6546  f.Rename(GetLogName() + "-backup", CDirEntry::fRF_Overwrite);
6547  }
6548  }
6549 
6550  m_LowDiskSpace = false;
6551  CDiagFileHandleHolder* new_handle;
6552  new_handle = new CDiagFileHandleHolder(GetLogName(), flags);
6553  new_handle->AddReference();
6554  if (new_handle->GetHandle() == -1) {
6555  new_handle->RemoveReference();
6556  new_handle = NULL;
6557  }
6558  else {
6559  // Need at least 20K of free space to write logs
6560  try {
6561  CDirEntry entry(GetLogName());
6562  m_LowDiskSpace = CFileUtil::GetFreeDiskSpace(entry.GetDir()) < 1024*20;
6563  }
6564  catch (const CException&) {
6565  // Ignore error - could not check free space for some reason.
6566  // Try to open the file anyway.
6567  }
6568  if (m_LowDiskSpace) {
6569  new_handle->RemoveReference();
6570  new_handle = NULL;
6571  }
6572  }
6573 
6574  CDiagFileHandleHolder* old_handle;
6575  {{
6576  CSpinGuard guard(*m_HandleLock);
6577  // Restart the timer even if failed to reopen the file.
6579  old_handle = m_Handle;
6580  m_Handle = new_handle;
6581  }}
6582 
6583  if (old_handle)
6584  old_handle->RemoveReference();
6585 
6586  if (!new_handle) {
6587  if ( !m_Messages.get() ) {
6588  m_Messages.reset(new TMessages);
6589  }
6590  }
6591  else if ( m_Messages.get() ) {
6592  // Flush the collected messages, if any, once the handle if available.
6593  // If the process was forked, ignore messages collected by the parent.
6596  ITERATE(TMessages, it, *m_Messages) {
6597  if (it->m_PID != pid) {
6598  continue;
6599  }
6600  string str = ComposeMessage(*it, 0);
6601  if (NcbiSys_write(new_handle->GetHandle(), str.data(), (unsigned)str.size()))
6602  {/*dummy*/}
6603  }
6604  m_Messages.reset();
6605  }
6606 
6607  s_ReopenEntered->Add(-1);
6608 }
6609 
6610 
6612 {
6613  // Period is longer than for CFileDiagHandler to prevent double-reopening
6614  if (!m_ReopenTimer->IsRunning() ||
6616  {
6617  if (s_ReopenEntered->Add(1) == 1 || !m_ReopenTimer->IsRunning()) {
6619  m_HavePosts = true;
6620  if (!m_ReopenTimer->IsRunning() ||
6622  {
6623  Reopen(fDefault);
6624  }
6625  }
6626  s_ReopenEntered->Add(-1);
6627  }
6628 
6629  // If the handle is not available, collect the messages until they
6630  // can be written.
6631  if ( m_Messages.get() ) {
6633  // Check again to make sure m_Messages still exists.
6634  if ( m_Messages.get() ) {
6635  // Limit number of stored messages to 1000
6636  if ( m_Messages->size() < 1000 ) {
6637  m_Messages->push_back(mess);
6638  }
6639  return;
6640  }
6641  }
6642 
6643  CDiagFileHandleHolder* handle;
6644  {{
6645  CSpinGuard guard(*m_HandleLock);
6646  handle = m_Handle;
6647  if (handle)
6648  handle->AddReference();
6649  }}
6650 
6651  if (handle) {
6652  string str = ComposeMessage(mess, 0);
6653  if (NcbiSys_write(handle->GetHandle(), str.data(), (unsigned)str.size()))
6654  {/*dummy*/}
6655 
6656  handle->RemoveReference();
6657  }
6658 }
6659 
6660 
6662 {
6663  return true;
6664 }
6665 
6666 
6668  EDiagFileType*) const
6669 {
6670  stringstream str_os;
6671  str_os << msg;
6672  return str_os.str();
6673 }
6674 
6675 
6677  size_t len,
6678  EDiagFileType /*file_type*/)
6679 {
6680  // Period is longer than for CFileDiagHandler to prevent double-reopening
6681  // In async mode only one thread is writing messages and there's no need
6682  // to use locks, but it's still necessary to check for nested reopening.
6683  if (!m_ReopenTimer->IsRunning() ||
6685  {
6686  if (s_ReopenEntered->Add(1) == 1) {
6687  Reopen(fDefault);
6688  }
6689  s_ReopenEntered->Add(-1);
6690  }
6691 
6692  if (NcbiSys_write(m_Handle->GetHandle(), buf, (unsigned)len))
6693  {/*dummy*/}
6694 
6695  // Skip collecting m_Messages - we don't have the original SDiagMessage
6696  // here and can not store it. If for some reason Reopen() fails in async
6697  // mode, some messages can be lost.
6698 }
6699 
6700 
6701 // CFileDiagHandler
6702 
6703 static bool s_SplitLogFile = false;
6704 
6705 extern void SetSplitLogFile(bool value)
6706 {
6708 }
6709 
6710 
6711 extern bool GetSplitLogFile(void)
6712 {
6713  return s_SplitLogFile;
6714 }
6715 
6716 
6717 bool s_IsSpecialLogName(const string& name)
6718 {
6719  return name.empty()
6720  || name == "-"
6721  || name == "/dev/null"
6722  || name == "/dev/stdout"
6723  || name == "/dev/stderr";
6724 }
6725 
6726 
6728  : m_Err(0),
6729  m_OwnErr(false),
6730  m_Log(0),
6731  m_OwnLog(false),
6732  m_Trace(0),
6733  m_OwnTrace(false),
6734  m_Perf(0),
6735  m_OwnPerf(false),
6736  m_ReopenTimer(new CStopWatch())
6737 {
6738  SetLogFile("-", eDiagFile_All, true);
6739 }
6740 
6741 
6743 {
6748  delete m_ReopenTimer;
6749 }
6750 
6751 
6752 void CFileDiagHandler::SetLogName(const string& log_name)
6753 {
6754  string abs_name = CDirEntry::IsAbsolutePath(log_name) ? log_name
6755  : CDirEntry::CreateAbsolutePath(log_name);
6756  TParent::SetLogName(abs_name);
6757 }
6758 
6759 
6761  bool* owned)
6762 {
6763  if (!ptr || !(*ptr)) {
6764  return;
6765  }
6766  _ASSERT(owned);
6767  if ( *owned ) {
6768  if (ptr != &m_Err && *ptr == m_Err) {
6769  // The handler is also used by m_Err
6770  _ASSERT(!m_OwnErr);
6771  m_OwnErr = true; // now it's owned as m_Err
6772  *owned = false;
6773  }
6774  else if (ptr != &m_Log && *ptr == m_Log) {
6775  _ASSERT(!m_OwnLog);
6776  m_OwnLog = true;
6777  *owned = false;
6778  }
6779  else if (ptr != &m_Trace && *ptr == m_Trace) {
6780  _ASSERT(!m_OwnTrace);
6781  m_OwnTrace = true;
6782  *owned = false;
6783  }
6784  else if (ptr != &m_Perf && *ptr == m_Perf) {
6785  _ASSERT(!m_OwnPerf);
6786  m_OwnPerf = true;
6787  *owned = false;
6788  }
6789  if (*owned) {
6790  delete *ptr;
6791  }
6792  }
6793  *owned = false;
6794  *ptr = 0;
6795 }
6796 
6797 
6799  bool* own_member,
6801  bool own)
6802 {
6803  if (*member == handler) {
6804  *member = 0;
6805  *own_member = false;
6806  }
6807  else {
6808  x_ResetHandler(member, own_member);
6809  }
6810  if (handler && own) {
6811  // Check if the handler is already owned
6812  if (member != &m_Err) {
6813  if (handler == m_Err && m_OwnErr) {
6814  own = false;
6815  }
6816  }
6817  if (member != &m_Log) {
6818  if (handler == m_Log && m_OwnLog) {
6819  own = false;
6820  }
6821  }
6822  if (member != &m_Trace) {
6823  if (handler == m_Trace && m_OwnTrace) {
6824  own = false;
6825  }
6826  }
6827  if (member != &m_Perf) {
6828  if (handler == m_Perf && m_OwnPerf) {
6829  own = false;
6830  }
6831  }
6832  }
6833  *member = handler;
6834  *own_member = own;
6835 }
6836 
6837 
6839 {
6840  if (!handler) {
6841  return;
6842  }
6843  if (m_Err == handler) {
6844  m_OwnErr = own;
6845  own = false;
6846  }
6847  if (m_Log == handler) {
6848  m_OwnLog = own;
6849  own = false;
6850  }
6851  if (m_Trace == handler) {
6852  m_OwnTrace = own;
6853  own = false;
6854  }
6855  if (m_Perf == handler) {
6856  m_OwnPerf = own;
6857  }
6858 }
6859 
6860 
6861 static bool
6862 s_CreateHandler(const string& fname,
6863  unique_ptr<CStreamDiagHandler_Base>& handler,
6865 {
6866  if ( fname.empty() || fname == "/dev/null") {
6867  handler.reset();
6868  return true;
6869  }
6870  if (fname == "-") {
6871  handler.reset(new CStreamDiagHandler(&NcbiCerr, true, kLogName_Stderr));
6872  return true;
6873  }
6874  unique_ptr<CFileHandleDiagHandler> fh(new CFileHandleDiagHandler(fname, file_type));
6875  if ( !fh->Valid() ) {
6876  ERR_POST_X(7, Info << "Failed to open log file: " << fname);
6877  return false;
6878  }
6879  handler.reset(fh.release());
6880  return true;
6881 }
6882 
6883 
6886  bool /*quick_flush*/)
6887 {
6888  bool special = s_IsSpecialLogName(file_name);
6889  unique_ptr<CStreamDiagHandler_Base> err_handler, log_handler,
6890  trace_handler, perf_handler;
6891  switch ( file_type ) {
6892  case eDiagFile_All:
6893  {
6894  // Remove known extension if any
6895  string adj_name = file_name;
6896  if ( !special ) {
6897  CDirEntry entry(file_name);
6898  string ext = entry.GetExt();
6899  if (ext == ".log" ||
6900  ext == ".err" ||
6901  ext == ".trace" ||
6902  ext == ".perf") {
6903  adj_name = entry.GetDir() + entry.GetBase();
6904  }
6905  }
6906  string err_name = special ? adj_name : adj_name + ".err";
6907  string log_name = special ? adj_name : adj_name + ".log";
6908  string trace_name = special ? adj_name : adj_name + ".trace";
6909  string perf_name = special ? adj_name : adj_name + ".perf";
6910 
6911  if ( s_SplitLogFile ) {
6912  if (!s_CreateHandler(err_name, err_handler, eDiagFile_Err))
6913  return false;
6914  if (!s_CreateHandler(log_name, log_handler, eDiagFile_Log))
6915  return false;
6916  if (!s_CreateHandler(trace_name, trace_handler, eDiagFile_Trace))
6917  return false;
6918  if (!s_CreateHandler(perf_name, perf_handler, eDiagFile_Perf))
6919  return false;
6920 
6921  x_SetHandler(&m_Err, &m_OwnErr, err_handler.release(), true);
6922  x_SetHandler(&m_Log, &m_OwnLog, log_handler.release(), true);
6923  x_SetHandler(&m_Trace, &m_OwnTrace, trace_handler.release(), true);
6924  x_SetHandler(&m_Perf, &m_OwnPerf, perf_handler.release(), true);
6925  }
6926  else {
6928  return false;
6929  if (!s_CreateHandler(perf_name, perf_handler, eDiagFile_Perf))
6930  return false;
6931 
6932  x_SetHandler(&m_Err, &m_OwnErr, err_handler.get(), true);
6933  x_SetHandler(&m_Log, &m_OwnLog, err_handler.get(), true);
6934  x_SetHandler(&m_Trace, &m_OwnTrace, err_handler.release(), true);
6935  x_SetHandler(&m_Perf, &m_OwnPerf, perf_handler.release(), true);
6936  }
6937 
6939  break;
6940  }
6941  case eDiagFile_Err:
6943  return false;
6944  x_SetHandler(&m_Err, &m_OwnErr, err_handler.release(), true);
6945  break;
6946  case eDiagFile_Log:
6947  if (!s_CreateHandler(file_name, log_handler, eDiagFile_Log))
6948  return false;
6949  x_SetHandler(&m_Log, &m_OwnLog, log_handler.release(), true);
6950  break;
6951  case eDiagFile_Trace:
6952  if (!s_CreateHandler(file_name, trace_handler, eDiagFile_Trace))
6953  return false;
6954  x_SetHandler(&m_Trace, &m_OwnTrace, trace_handler.release(), true);
6955  break;
6956  case eDiagFile_Perf:
6957  if (!s_CreateHandler(file_name, perf_handler, eDiagFile_Perf))
6958  return false;
6959  x_SetHandler(&m_Perf, &m_OwnPerf, perf_handler.release(), true);
6960  break;
6961  }
6962  if (file_name == "") {
6964  }
6965  else if (file_name == "-") {
6967  }
6968  else {
6970  }
6971  return true;
6972 }
6973 
6974 
6976 {
6977  switch ( file_type ) {
6978  case eDiagFile_Err:
6979  return m_Err->GetLogName();
6980  case eDiagFile_Log:
6981  return m_Log->GetLogName();
6982  case eDiagFile_Trace:
6983  return m_Trace->GetLogName();
6984  case eDiagFile_Perf:
6985  return m_Perf->GetLogName();
6986  case eDiagFile_All:
6987  break; // kEmptyStr
6988  }
6989  return kEmptyStr;
6990 }
6991 
6992 
6994 {
6996  switch ( file_type ) {
6997  case eDiagFile_Err:
6998  handler = m_Err;
6999  break;
7000  case eDiagFile_Log:
7001  handler = m_Log;
7002  break;
7003  case eDiagFile_Trace:
7004  handler = m_Trace;
7005  break;
7006  case eDiagFile_Perf:
7007  handler = m_Perf;
7008  break;
7009  case eDiagFile_All:
7010  return 0;
7011  }
7012  return handler ? handler->GetStream() : 0;
7013 }
7014 
7015 
7018  bool own)
7019 {
7020  switch ( file_type ) {
7021  case eDiagFile_All:
7022  // Must set all handlers
7023  case eDiagFile_Err:
7024  x_SetHandler(&m_Err, &m_OwnErr, handler, own);
7025  if (file_type != eDiagFile_All) break;
7026  case eDiagFile_Log:
7027  x_SetHandler(&m_Log, &m_OwnLog, handler, own);
7028  if (file_type != eDiagFile_All) break;
7029  case eDiagFile_Trace:
7031  if (file_type != eDiagFile_All) break;
7032  case eDiagFile_Perf:
7034  if (file_type != eDiagFile_All) break;
7035  }
7036 }
7037 
7038 
7040 {
7041  s_ReopenEntered->Add(1);
7042 
7043  if (flags & fCheck && m_ReopenTimer->IsRunning()) {
7045  s_ReopenEntered->Add(-1);
7046  return;
7047  }
7048  }
7049  if ( m_Err ) {
7050  m_Err->Reopen(flags);
7051  }
7052  if ( m_Log && m_Log != m_Err ) {
7053  m_Log->Reopen(flags);
7054  }
7055  if ( m_Trace && m_Trace != m_Log && m_Trace != m_Err ) {
7056  m_Trace->Reopen(flags);
7057  }
7058  if ( m_Perf ) {
7059  m_Perf->Reopen(flags);
7060  }
7062 
7063  s_ReopenEntered->Add(-1);
7064 }
7065 
7066 
7068 {
7069  if ( IsSetDiagPostFlag(eDPF_AppLog, msg.m_Flags) ) {
7072  }
7073  else {
7074  switch ( msg.m_Severity ) {
7075  case eDiag_Info:
7076  case eDiag_Trace:
7077  return eDiagFile_Trace;
7078  break;
7079  default:
7080  return eDiagFile_Err;
7081  }
7082  }
7083  // Never gets here anyway.
7084  return eDiagFile_All;
7085 }
7086 
7087 
7089 {
7090  switch ( file_type ) {
7091  case eDiagFile_Err: return m_Err;
7092  case eDiagFile_Log: return m_Log;
7093  case eDiagFile_Trace: return m_Trace;
7094  case eDiagFile_Perf: return m_Perf;
7095  default: return 0;
7096  }
7097 }
7098 
7099 
7101 {
7102  // Check time and re-open the streams
7103  if (!m_ReopenTimer->IsRunning() ||
7105  {
7106  if (s_ReopenEntered->Add(1) == 1 || !m_ReopenTimer->IsRunning()) {
7108  if (!m_ReopenTimer->IsRunning() ||
7110  {
7111  Reopen(fDefault);
7112  }
7113  }
7114  s_ReopenEntered->Add(-1);
7115  }
7116 
7117  // Output the message
7119  if (handler)
7120  handler->Post(mess);
7121 }
7122 
7123 
7125 {
7127  return handler && handler->AllowAsyncWrite(msg);
7128 }
7129 
7130 
7132  EDiagFileType* file_type) const
7133 {
7134  EDiagFileType ft = x_GetDiagFileType(msg);
7135  if ( file_type ) {
7136  *file_type = ft;
7137  }
7139  return handler ? handler->ComposeMessage(msg, file_type) : kEmptyStr;
7140 }
7141 
7142 
7144  size_t len,
7146 {
7147  // In async mode only one thread is writing messages and there's no need
7148  // to use locks, but it's still necessary to check for nested reopening.
7149  if (!m_ReopenTimer->IsRunning() ||
7151  {
7152  if (s_ReopenEntered->Add(1) == 1) {
7153  Reopen(fDefault);
7154  }
7155  s_ReopenEntered->Add(-1);
7156  }
7157 
7159  if ( handler ) {
7160  handler->WriteMessage(buf, len, file_type);
7161  }
7162 }
7163 
7164 
7166 {
7169 
7171  string* m_Composed;
7173 };
7174 
7175 
7177 {
7178 public:
7179  CAsyncDiagThread(const string& thread_suffix);
7180  virtual ~CAsyncDiagThread(void);
7181 
7182  virtual void* Main(void);
7183  void Stop(void);
7184 
7190 #ifdef NCBI_HAVE_CONDITIONAL_VARIABLE
7191  CConditionVariable m_QueueCond;
7192  CConditionVariable m_DequeueCond;
7193 #else
7196 #endif
7197  deque<SAsyncDiagMessage> m_MsgQueue;
7199 };
7200 
7201 
7202 /// Maximum number of messages that allowed to be in the queue for
7203 /// asynchronous processing.
7204 NCBI_PARAM_DECL(Uint4, Diag, Max_Async_Queue_Size);
7205 NCBI_PARAM_DEF_EX(Uint4, Diag, Max_Async_Queue_Size, 10000, eParam_NoThread,
7206  DIAG_MAX_ASYNC_QUEUE_SIZE);
7207 
7208 
7210  : m_AsyncThread(NULL)
7211 {}
7212 
7214 {
7216 }
7217 
7218 void
7220 {
7222 }
7223 
7224 void
7226 {
7229  try {
7230  m_AsyncThread->Run();
7231  }
7232  catch (const CThreadException&) {
7234  m_AsyncThread = NULL;
7235  throw;
7236  }
7238  SetDiagHandler(this, false);
7239 }
7240 
7241 void
7243 {
7244  if (!m_AsyncThread)
7245  return;
7246 
7247  _ASSERT(GetDiagHandler(false) == this);
7249  m_AsyncThread->Stop();
7251  m_AsyncThread = NULL;
7252 }
7253 
7254 string
7256 {
7258 }
7259 
7260 void
7262 {
7264 }
7265 
7266 void
7268 {
7270  SAsyncDiagMessage async;
7271  if (thr->m_SubHandler->AllowAsyncWrite(mess)) {
7272  async.m_Composed = new string(thr->m_SubHandler->
7273  ComposeMessage(mess, &async.m_FileType));
7274  }
7275  else {
7276  async.m_Message = new SDiagMessage(mess);
7277  }
7278 
7279  static CSafeStatic<NCBI_PARAM_TYPE(Diag, Max_Async_Queue_Size)> s_MaxAsyncQueueSizeParam;
7280  if (mess.m_Severity < GetDiagDieLevel()) {
7281  CFastMutexGuard guard(thr->m_QueueLock);
7282  while (Uint4(thr->m_MsgsInQueue.Get()) >= s_MaxAsyncQueueSizeParam->Get())
7283  {
7284  ++thr->m_CntWaiters;
7285 #ifdef NCBI_HAVE_CONDITIONAL_VARIABLE
7286  thr->m_DequeueCond.WaitForSignal(thr->m_QueueLock);
7287 #else
7288  guard.Release();
7289  thr->m_QueueSem.Wait();
7290  guard.Guard(thr->m_QueueLock);
7291 #endif
7292  --thr->m_CntWaiters;
7293  }
7294  thr->m_MsgQueue.push_back(async);
7295  if (thr->m_MsgsInQueue.Add(1) == 1) {
7296 #ifdef NCBI_HAVE_CONDITIONAL_VARIABLE
7297  thr->m_QueueCond.SignalSome();
7298 #else
7299  thr->m_QueueSem.Post();
7300 #endif
7301  }
7302  }
7303  else {
7304  thr->Stop();
7305  thr->m_SubHandler->Post(mess);
7306  }
7307 }
7308 
7309 
7310 CAsyncDiagThread::CAsyncDiagThread(const string& thread_suffix)
7311  : m_NeedStop(false),
7312  m_CntWaiters(0),
7313  m_SubHandler(NULL),
7315  m_QueueSem(0, 100),
7316  m_DequeueSem(0, 10000000),
7317 #endif
7318  m_ThreadSuffix(thread_suffix)
7319 {
7320  m_MsgsInQueue.Set(0);
7321 }
7322 
7324 {}
7325 
7326 
7327 NCBI_PARAM_DECL(size_t, Diag, Async_Buffer_Size);
7328 NCBI_PARAM_DEF_EX(size_t, Diag, Async_Buffer_Size, 32768,
7329  eParam_NoThread, DIAG_ASYNC_BUFFER_SIZE);
7330 
7331 NCBI_PARAM_DECL(size_t, Diag, Async_Buffer_Max_Lines);
7332 NCBI_PARAM_DEF_EX(size_t, Diag, Async_Buffer_Max_Lines, 100,
7333  eParam_NoThread, DIAG_ASYNC_BUFFER_MAX_LINES);
7334 
7335 
7337 {
7338  char* data;
7339  size_t size;
7340  size_t pos;
7341  size_t lines;
7342  size_t max_lines;
7343 
7345  : data(0), size(0), pos(0), lines(0)
7346  {
7347  size = NCBI_PARAM_TYPE(Diag, Async_Buffer_Size)::GetDefault();
7348  if ( size ) {
7349  data = new char[size];
7350  }
7351  max_lines = NCBI_PARAM_TYPE(Diag, Async_Buffer_Max_Lines)::GetDefault();
7352  }
7353 
7355  {
7356  if ( data ) {
7357  delete[](data);
7358  }
7359  }
7360 
7361  bool IsEmpty(void)
7362  {
7363  return pos != 0;
7364  }
7365 
7366  void Clear(void)
7367  {
7368  pos = 0;
7369  lines = 0;
7370  }
7371 
7372  bool Append(const string& str)
7373  {
7374  if (!size || pos + str.size() >= size || lines >= max_lines) {
7375  return false;
7376  }
7377  memcpy(&data[pos], str.data(), str.size());
7378  pos += str.size();
7379  lines++;
7380  return true;
7381  }
7382 };
7383 
7384 
7385 /// Number of messages processed as a single batch by the asynchronous
7386 /// handler.
7387 NCBI_PARAM_DECL(int, Diag, Async_Batch_Size);
7388 NCBI_PARAM_DEF_EX(int, Diag, Async_Batch_Size, 10, eParam_NoThread,
7389  DIAG_ASYNC_BATCH_SIZE);
7390 
7391 
7392 void*
7394 {
7395  if (!m_ThreadSuffix.empty()) {
7397  string thr_name = app ? app->GetProgramDisplayName() : "";
7398  thr_name += m_ThreadSuffix;
7399  SetCurrentThreadName(thr_name);
7400  }
7401 
7402  const int batch_size = NCBI_PARAM_TYPE(Diag, Async_Batch_Size)::GetDefault();
7403 
7404  const size_t buf_count = size_t(eDiagFile_All) + 1;
7405  SMessageBuffer* buffers[buf_count];
7406  for (size_t i = 0; i < buf_count; ++i) {
7407  buffers[i] = 0;
7408  }
7409 
7410  deque<SAsyncDiagMessage> save_msgs;
7411  while (!m_NeedStop) {
7412  {{
7414  while (m_MsgQueue.size() == 0 && !m_NeedStop) {
7415  if (m_MsgsInQueue.Get() != 0)
7416  abort();
7417 #ifdef NCBI_HAVE_CONDITIONAL_VARIABLE
7418  m_QueueCond.WaitForSignal(m_QueueLock);
7419 #else
7420  guard.Release();
7421  m_QueueSem.Wait();
7422  guard.Guard(m_QueueLock);
7423 #endif
7424  }
7425  save_msgs.swap(m_MsgQueue);
7426  }}
7427 
7428 drain_messages:
7429  int queue_counter = 0;
7430  while (!save_msgs.empty()) {
7431  SAsyncDiagMessage msg = save_msgs.front();
7432  save_msgs.pop_front();
7433  if ( msg.m_Composed ) {
7434  SMessageBuffer* buf = buffers[msg.m_FileType];
7435  if ( !buf ) {
7436  buf = new SMessageBuffer;
7437  buffers[msg.m_FileType] = buf;
7438  }
7439  if ( !buf->size ) {
7440  // Do not use buffering.
7441  m_SubHandler->WriteMessage(msg.m_Composed->data(),
7442  msg.m_Composed->size(), msg.m_FileType);
7443  }
7444  else if ( !buf->Append(*msg.m_Composed) ) {
7445  // Not enough space in the buffer or no waiters,
7446  // try to flush if not empty.
7447  if ( !buf->IsEmpty() ) {
7448  m_SubHandler->WriteMessage(buf->data, buf->pos, msg.m_FileType);
7449  buf->Clear();
7450  }
7451  if ( !buf->Append(*msg.m_Composed) ) {
7452  // The message is too long to fit in the buffer.
7453  m_SubHandler->WriteMessage(msg.m_Composed->data(),
7454  msg.m_Composed->size(), msg.m_FileType);
7455  }
7456  }
7457  delete msg.m_Composed;
7458  }
7459  else {
7460  _ASSERT(msg.m_Message);
7461  m_SubHandler->Post(*msg.m_Message);
7462  delete msg.m_Message;
7463  }
7464  if (++queue_counter >= batch_size || save_msgs.empty()) {
7465  m_MsgsInQueue.Add(-queue_counter);
7466  queue_counter = 0;
7467  if (m_CntWaiters != 0) {
7468 #ifdef NCBI_HAVE_CONDITIONAL_VARIABLE
7469  m_DequeueCond.SignalSome();
7470 #else
7471  m_DequeueSem.Post();
7472 #endif
7473  }
7474  }
7475  }
7476  // Flush all buffers when the queue is empty and there are no waiters.
7477  if (m_CntWaiters == 0) {
7478  for (size_t i = 0; i < buf_count; ++i) {
7479  if ( !buffers[i] ) {
7480  continue;
7481  }
7482  if ( !buffers[i]->IsEmpty() ) {
7483  m_SubHandler->WriteMessage(buffers[i]->data,
7484  buffers[i]->pos, EDiagFileType(i));
7485  buffers[i]->Clear();
7486  }
7487  }
7488  }
7489  }
7490  if (m_MsgQueue.size() != 0) {
7491  save_msgs.swap(m_MsgQueue);
7492  goto drain_messages;
7493  }
7494 
7495  for (size_t i = 0; i < buf_count; ++i) {
7496  if ( !buffers[i] ) {
7497  continue;
7498  }
7499  if ( !buffers[i]->IsEmpty() ) {
7500  m_SubHandler->WriteMessage(buffers[i]->data,
7501  buffers[i]->pos, EDiagFileType(i));
7502  }
7503  delete buffers[i];
7504  }
7505 
7506  return NULL;
7507 }
7508 
7509 void
7511 {
7512  m_NeedStop = true;
7513  try {
7514 #ifdef NCBI_HAVE_CONDITIONAL_VARIABLE
7515  m_QueueCond.SignalAll();
7516 #else
7517  m_QueueSem.Post(10);
7518 #endif
7519  Join();
7520  }
7521  catch (const CException& ex) {
7522  ERR_POST_X(24, Critical
7523  << "Error while stopping thread for AsyncDiagHandler: " << ex);
7524  }
7525 }
7526 
7527 
7528 extern bool SetLogFile(const string& file_name,
7530  bool quick_flush)
7531 {
7532  // Check if a non-existing dir is specified
7533  if ( !s_IsSpecialLogName(file_name) ) {
7534  string dir = CFile(file_name).GetDir();
7535  if ( !dir.empty() && !CDir(dir).Exists() ) {
7536  return false;
7537  }
7538  }
7539 
7540  if (file_type != eDiagFile_All) {
7541  // Auto-split log file
7542  SetSplitLogFile(true);
7543  }
7544  if ( !s_SplitLogFile ) {
7545  if (file_type != eDiagFile_All) {
7546  ERR_POST_X(8, Info <<
7547  "Failed to set log file for the selected event type: "
7548  "split log is disabled");
7549  return false;
7550  }
7551  // Check special filenames
7552  if ( file_name.empty() || file_name == "/dev/null" ) {
7553  // no output
7554  SetDiagStream(0, quick_flush, 0, 0, kLogName_None);
7555  }
7556  else if (file_name == "-") {
7557  // output to stderr
7558  SetDiagStream(&NcbiCerr, quick_flush, 0, 0, kLogName_Stderr);
7559  }
7560  else {
7561  // output to file
7562  unique_ptr<CFileDiagHandler> fhandler(new CFileDiagHandler());
7563  if ( !fhandler->SetLogFile(file_name, eDiagFile_All, quick_flush) ) {
7564  ERR_POST_X(9, Info << "Failed to initialize log: " << file_name);
7565  return false;
7566  }
7567  SetDiagHandler(fhandler.release());
7568  }
7569  }
7570  else {
7572  dynamic_cast<CFileDiagHandler*>(GetDiagHandler());
7573  if ( !handler ) {
7574  bool old_ownership = false;
7575  CStreamDiagHandler_Base* sub_handler =
7576  dynamic_cast<CStreamDiagHandler_Base*>(GetDiagHandler(false, &old_ownership));
7577  if ( !sub_handler ) {
7578  old_ownership = false;
7579  }
7580  // Install new handler, try to re-use the old one
7581  unique_ptr<CFileDiagHandler> fhandler(new CFileDiagHandler());
7582  if ( sub_handler && file_type != eDiagFile_All) {
7583  // If we are going to set all handlers, no need to save the old one.
7584  if ( old_ownership ) {
7585  GetDiagHandler(true); // Take ownership!
7586  }
7587  // Set all three handlers to the old one.
7588  fhandler->SetSubHandler(sub_handler, eDiagFile_All, old_ownership);
7589  }
7590  if ( fhandler->SetLogFile(file_name, file_type, quick_flush) ) {
7591  // This will delete the old handler in case of eDiagFile_All.
7592  // Otherwise the new handler will remember the ownership.
7593  SetDiagHandler(fhandler.release());
7594  return true;
7595  }
7596  else {
7597  // Restore the old handler's ownership if necessary.
7598  if ( old_ownership ) {
7599  SetDiagHandler(sub_handler, true);
7600  }
7601  return false;
7602  }
7603  }
7604  // Update the existing handler
7606  return handler->SetLogFile(file_name, file_type, quick_flush);
7607  }
7608  return true;
7609 }
7610 
7611 
7613 {
7615  CFileDiagHandler* fhandler =
7616  dynamic_cast<CFileDiagHandler*>(handler);
7617  if ( fhandler ) {
7618  return fhandler->GetLogFile(file_type);
7619  }
7620  CFileHandleDiagHandler* fhhandler =
7621  dynamic_cast<CFileHandleDiagHandler*>(handler);
7622  if ( fhhandler ) {
7623  return fhhandler->GetLogName();
7624  }
7625  return kEmptyStr;
7626 }
7627 
7628 
7629 extern string GetLogFile(void)
7630 {
7632  return handler ? handler->GetLogName() : kEmptyStr;
7633 }
7634 
7635 
7636 extern bool IsDiagStream(const CNcbiOstream* os)
7637 {
7639  = dynamic_cast<CStreamDiagHandler_Base*>(CDiagBuffer::sm_Handler);
7640  return (sdh && sdh->GetStream() == os);
7641 }
7642 
7643 
7644 extern void SetDiagErrCodeInfo(CDiagErrCodeInfo* info, bool can_delete)
7645 {
7647  if ( CDiagBuffer::sm_CanDeleteErrCodeInfo &&
7648  CDiagBuffer::sm_ErrCodeInfo )
7649  delete CDiagBuffer::sm_ErrCodeInfo;
7650  CDiagBuffer::sm_ErrCodeInfo = info;
7651  CDiagBuffer::sm_CanDeleteErrCodeInfo = can_delete;
7652 }
7653 
7654 extern bool IsSetDiagErrCodeInfo(void)
7655 {
7656  return (CDiagBuffer::sm_ErrCodeInfo != 0);
7657 }
7658 
7659 extern CDiagErrCodeInfo* GetDiagErrCodeInfo(bool take_ownership)
7660 {
7662  if (take_ownership) {
7663  _ASSERT(CDiagBuffer::sm_CanDeleteErrCodeInfo);
7664  CDiagBuffer::sm_CanDeleteErrCodeInfo = false;
7665  }
7666  return CDiagBuffer::sm_ErrCodeInfo;
7667 }
7668 
7669 
7670 extern void SetDiagFilter(EDiagFilter what, const char* filter_str)
7671 {
7673  if (what == eDiagFilter_Trace || what == eDiagFilter_All)
7674  s_TraceFilter->Fill(filter_str);
7675 
7676  if (what == eDiagFilter_Post || what == eDiagFilter_All)
7677  s_PostFilter->Fill(filter_str);
7678 }
7679 
7680 
7681 extern string GetDiagFilter(EDiagFilter what)
7682 {
7684  if (what == eDiagFilter_Trace)
7685  return s_TraceFilter->GetFilterStr();
7686 
7687  if (what == eDiagFilter_Post)
7688  return s_PostFilter->GetFilterStr();
7689 
7690  return kEmptyStr;
7691 }
7692 
7693 
7694 extern void AppendDiagFilter(EDiagFilter what, const char* filter_str)
7695 {
7697  if (what == eDiagFilter_Trace || what == eDiagFilter_All)
7698  s_TraceFilter->Append(filter_str);
7699 
7700  if (what == eDiagFilter_Post || what == eDiagFilter_All)
7701  s_PostFilter->Append(filter_str);
7702 }
7703 
7704 
7705 
7706 ///////////////////////////////////////////////////////
7707 // CNcbiDiag::
7708 
7710  : m_Severity(sev),
7711  m_ErrCode(0),
7712  m_ErrSubCode(0),
7713  m_Buffer(GetDiagBuffer()),
7714  m_PostFlags(ForceImportantFlags(post_flags)),
7715  m_OmitStackTrace(false)
7716 {
7717 }
7718 
7719 
7721  EDiagSev sev, TDiagPostFlags post_flags)
7722  : m_Severity(sev),
7723  m_ErrCode(0),
7724  m_ErrSubCode(0),
7725  m_Buffer(GetDiagBuffer()),
7726  m_PostFlags(ForceImportantFlags(post_flags)),
7727  m_OmitStackTrace(false),
7728  m_CompileInfo(info)
7729 {
7730 }
7731 
7733 {
7734  m_Buffer.Detach(this);
7735 }
7736 
7738 {
7741  (CDiagBuffer::s_GetPostFlags() & eDPF_ImportantFlagsMask);
7742  }
7743  return flags;
7744 }
7745 
7746 const CNcbiDiag& CNcbiDiag::SetFile(const char* file) const
7747 {
7749  return *this;
7750 }
7751 
7752 
7753 const CNcbiDiag& CNcbiDiag::SetModule(const char* module) const
7754 {
7755  m_CompileInfo.SetModule(module);
7756  return *this;
7757 }
7758 
7759 
7760 const CNcbiDiag& CNcbiDiag::SetClass(const char* nclass) const
7761 {
7762  m_CompileInfo.SetClass(nclass);
7763  return *this;
7764 }
7765 
7766 
7767 const CNcbiDiag& CNcbiDiag::SetFunction(const char* function) const
7768 {
7769  m_CompileInfo.SetFunction(function);
7770  return *this;
7771 }
7772 
7773 
7775 {
7776  EDiagSev current_sev = GetSeverity();
7777  if (current_sev == eDiag_Fatal) {
7778  return true;
7779  }
7781  if (GetSeverity() == eDiag_Trace) {
7782  // check for trace filter
7783  return s_TraceFilter->Check(*this, ex) != eDiagFilter_Reject;
7784  }
7785  // check for post filter
7786  return s_PostFilter->Check(*this, ex) != eDiagFilter_Reject;
7787 }
7788 
7789 
7791  const CStackTrace& stacktrace) const
7792 {
7793  if ( !stacktrace.Empty() ) {
7794  stacktrace.SetPrefix(" ");
7795  stringstream os;
7796  s_FormatStackTrace(os, stacktrace);
7797  *this << os.str();
7798  }
7799  return *this;
7800 }
7801 
7802 static string
7804 {
7805  string text(pex->GetMsg());
7806  stringstream os;
7807  pex->ReportExtra(os);
7808  string s = os.str();
7809  if ( !s.empty() ) {
7810  text += " (";
7811  text += s;
7812  text += ')';
7813  }
7814  return text;
7815 }
7816 
7817 const CNcbiDiag& CNcbiDiag::x_Put(const CException& ex) const
7818 {
7819  if (m_Buffer.SeverityDisabled(GetSeverity()) || !CheckFilters(&ex)) {
7820  return *this;
7821  }
7823  CDiagCollectGuard* guard = thr_data.GetCollectGuard();
7824  EDiagSev print_sev = AdjustApplogPrintableSeverity(CDiagBuffer::sm_PostSeverity);
7825  EDiagSev collect_sev = print_sev;
7826  if ( guard ) {
7827  print_sev = AdjustApplogPrintableSeverity(guard->GetPrintSeverity());
7828  collect_sev = guard->GetCollectSeverity();
7829  }
7830 
7831  const CException* pex;
7832  const CException* main_pex = NULL;
7833  stack<const CException*> pile;
7834  // invert the order
7835  for (pex = &ex; pex; pex = pex->GetPredecessor()) {
7836  pile.push(pex);
7837  if (!main_pex && pex->HasMainText())
7838  main_pex = pex;
7839  }
7840  if (!main_pex)
7841  main_pex = pile.top();
7842  if ( !IsOssEmpty(*m_Buffer.m_Stream) ) {
7843  *this << "(" << main_pex->GetType() << "::"
7844  << main_pex->GetErrCodeString() << ") "
7845  << s_GetExceptionText(main_pex);
7846  }
7847  else {
7848  *this << main_pex->GetType() << "::"
7849  << main_pex->GetErrCodeString() << " "
7850  << s_GetExceptionText(main_pex);
7851  }
7852  for (; !pile.empty(); pile.pop()) {
7853  pex = pile.top();
7854  string text(s_GetExceptionText(pex));
7855  const CStackTrace* stacktrace = pex->GetStackTrace();
7856  if ( stacktrace ) {
7857  stringstream os;
7858  s_FormatStackTrace(os, *stacktrace);
7859  m_OmitStackTrace = true;
7860  text += os.str();
7861  }
7862  string err_type(pex->GetType());
7863  err_type += "::";
7864  err_type += pex->GetErrCodeString();
7865 
7866  EDiagSev pex_sev = pex->GetSeverity();
7867  if (CompareDiagPostLevel(GetSeverity(), print_sev) < 0) {
7868  if (CompareDiagPostLevel(pex_sev, collect_sev) < 0)
7869  pex_sev = collect_sev;
7870  }
7871  else {
7872  if (CompareDiagPostLevel(pex_sev, print_sev) < 0)
7873  pex_sev = print_sev;
7874  }
7875  if (CompareDiagPostLevel(GetSeverity(), pex_sev) < 0)
7876  pex_sev = GetSeverity();
7877 
7878  SDiagMessage diagmsg
7879  (pex_sev,
7880  text.c_str(),
7881  text.size(),
7882  pex->GetFile().c_str(),
7883  pex->GetLine(),
7884  GetPostFlags(),
7885  NULL,
7886  pex->GetErrCode(),
7887  0,
7888  err_type.c_str(),
7889  pex->GetModule().c_str(),
7890  pex->GetClass().c_str(),
7891  pex->GetFunction().c_str());
7892 
7893  if ( pex->IsSetFlag(CException::fConsole) ) {
7894  diagmsg.m_Flags |= eDPF_IsConsole;
7895  }
7896 
7897  m_Buffer.PrintMessage(diagmsg, *this);
7898  }
7899 
7900  return *this;
7901 }
7902 
7903 
7904 bool CNcbiDiag::StrToSeverityLevel(const char* str_sev, EDiagSev& sev)
7905 {
7906  if (!str_sev || !*str_sev) {
7907  return false;
7908  }
7909  // Digital value
7910  int nsev = NStr::StringToNonNegativeInt(str_sev);
7911 
7912  if (nsev > eDiagSevMax) {
7913  nsev = eDiagSevMax;
7914  } else if ( nsev == -1 ) {
7915  // String value
7916  for (int s = eDiagSevMin; s <= eDiagSevMax; s++) {
7918  str_sev) == 0) {
7919  nsev = s;
7920  break;
7921  }
7922  }
7923  }
7924  sev = EDiagSev(nsev);
7925  // Unknown value
7926  return sev >= eDiagSevMin && sev <= eDiagSevMax;
7927 }
7928 
7930  const char* message)
7931 {
7932  CNcbiDiag(info, NCBI_NS_NCBI::eDiag_Fatal) << message << Endm;
7933  // DiagFatal is non-returnable, so force aborting even if the above
7934  // call has returned.
7935  Abort();
7936 }
7937 
7939  const char* message)
7940 {
7941  CNcbiDiag(info, NCBI_NS_NCBI::eDiag_Fatal) << message << Endm;
7942 }
7943 
7945  const char* expression,
7946  const char* message)
7947 {
7949  "Assertion failed: (" <<
7950  (expression ? expression : "") << ") " <<
7951  (message ? message : "") << Endm;
7952  Abort();
7953 }
7954 
7956  const CDiagCompileInfo& info,
7957  const char* expression,
7958  const char* message)
7959 {
7961  DiagAssert(info, expression, message);
7962  }
7963 }
7964 
7966  const char* _DEBUG_ARG(expression),
7967  const char* message)
7968 {
7969 #ifdef _DEBUG
7971  DiagAssert(info, expression, message);
7972  }
7973 #endif
7974  throw CCoreException(info, 0, CCoreException::eCore, message);
7975 }
7976 
7977 ///////////////////////////////////////////////////////
7978 // CDiagRestorer::
7979 
7981 {
7983  const CDiagBuffer& buf = GetDiagBuffer();
7984  m_PostPrefix = buf.m_PostPrefix;
7985  m_PrefixList = buf.m_PrefixList;
7986  m_PostFlags = buf.sx_GetPostFlags();
7987  m_PostSeverity = buf.sm_PostSeverity;
7988  m_PostSeverityChange = buf.sm_PostSeverityChange;
7989  m_IgnoreToDie = buf.sm_IgnoreToDie;
7990  m_DieSeverity = buf.sm_DieSeverity;
7991  m_TraceDefault = buf.sm_TraceDefault;
7992  m_TraceEnabled = buf.sm_TraceEnabled;
7993  m_Handler = buf.sm_Handler;
7994  m_CanDeleteHandler = buf.sm_CanDeleteHandler;
7995  m_ErrCodeInfo = buf.sm_ErrCodeInfo;
7996  m_CanDeleteErrCodeInfo = buf.sm_CanDeleteErrCodeInfo;
7998 
7999  // avoid premature cleanup
8000  buf.sm_CanDeleteHandler = false;
8001  buf.sm_CanDeleteErrCodeInfo = false;
8002 }
8003 
8005 {
8006  {{
8008  CDiagBuffer& buf = GetDiagBuffer();
8009  buf.m_PostPrefix = m_PostPrefix;
8010  buf.m_PrefixList = m_PrefixList;
8011  buf.sx_GetPostFlags() = m_PostFlags;
8012  buf.sm_PostSeverity = m_PostSeverity;
8013  buf.sm_PostSeverityChange = m_PostSeverityChange;
8014  buf.sm_IgnoreToDie = m_IgnoreToDie;
8015  buf.sm_DieSeverity = m_DieSeverity;
8016  buf.sm_TraceDefault = m_TraceDefault;
8017  buf.sm_TraceEnabled = m_TraceEnabled;
8018  }}
8022 }
8023 
8024 
8025 //////////////////////////////////////////////////////
8026 // internal diag. handler classes for compatibility:
8027 
8029 {
8030 public:
8032  : m_Func(func), m_Data(data), m_Cleanup(cleanup)
8033  { }
8035  {
8036  if (m_Cleanup) {
8037  m_Cleanup(m_Data);
8038  }
8039  }
8040  virtual void Post(const SDiagMessage& mess) { m_Func(mess); }
8041 
8042 private:
8044  void* m_Data;
8046 };
8047 
8048 
8049 extern void SetDiagHandler(FDiagHandler func,
8050  void* data,
8052 {
8054 }
8055 
8056 
8058 {
8059 public:
8061  bool quick_flush = true,
8062  FDiagCleanup cleanup = 0,
8063  void* cleanup_data = 0,
8064  const string& stream_name = kEmptyStr)
8065  : CStreamDiagHandler(os, quick_flush, stream_name),
8066  m_Cleanup(cleanup), m_CleanupData(cleanup_data)
8067  {
8068  }
8069 
8071  {
8072  if (m_Cleanup) {
8074  }
8075  }
8076 
8077 private:
8080 };
8081 
8082 
8083 extern void SetDiagStream(CNcbiOstream* os,
8084  bool quick_flush,
8086  void* cleanup_data,
8087  const string& stream_name)
8088 {
8089  string str_name = stream_name;
8090  if ( str_name.empty() ) {
8091  if (os == &cerr) {
8092  str_name = kLogName_Stderr;
8093  }
8094  else if (os == &cout) {
8095  str_name = kLogName_Stdout;
8096  }
8097  else {
8098  str_name = kLogName_Stream;
8099  }
8100  }
8101  NCBI_LSAN_DISABLE_GUARD; // new CCompatStreamDiagHandler
8103  new CCompatStreamDiagHandler(os, quick_flush, cleanup, cleanup_data, str_name)
8104  );
8105 }
8106 
8107 
8109 {
8110  CDiagHandler* diagh = GetDiagHandler();
8111  if ( !diagh ) {
8112  return 0;
8113  }
8115  dynamic_cast<CStreamDiagHandler_Base*>(diagh);
8116  // This can also be CFileDiagHandler, check it later
8117  if ( sh && sh->GetStream() ) {
8118  return sh->GetStream();
8119  }
8120  CFileDiagHandler* fh =
8121  dynamic_cast<CFileDiagHandler*>(diagh);
8122  if ( fh ) {
8123  return fh->GetLogStream(eDiagFile_Err);
8124  }
8125  return 0;
8126 }
8127 
8128 
8129 extern void SetDoubleDiagHandler(void)
8130 {
8131  ERR_POST_X(10, Error << "SetDoubleDiagHandler() is not implemented");
8132 }
8133 
8134 
8135 //////////////////////////////////////////////////////
8136 // Abort handler
8137 
8138 
8140 
8142 {
8143  s_UserAbortHandler = func;
8144 }
8145 
8146 
8147 extern void Abort(void)
8148 {
8149  // If there is a user abort handler then call it
8150  if ( s_UserAbortHandler )
8152 
8153  // If there's no handler or application is still running
8154 
8155  // Check environment variable for silent exit
8156  const TXChar* value = NcbiSys_getenv(_TX("DIAG_SILENT_ABORT"));
8157  if (value && (*value == _TX('Y') || *value == _TX('y') || *value == _TX('1'))) {
8158  ::fflush(0);
8159  ::_exit(255);
8160  }
8161  else if (value && (*value == _TX('N') || *value == _TX('n') || *value == _TX('0'))) {
8162  ::abort();
8163  }
8164  else {
8165 #if defined(NDEBUG)
8166  ::fflush(0);
8167  ::_exit(255);
8168 #else
8169  ::abort();
8170 #endif
8171  }
8172 }
8173 
8174 
8175 ///////////////////////////////////////////////////////
8176 // CDiagErrCodeInfo::
8177 //
8178 
8180  : m_Message(kEmptyStr),
8181  m_Explanation(kEmptyStr),
8182  m_Severity(-1)
8183 {
8184  return;
8185 }
8186 
8187 
8189 {
8190  CNcbiIfstream is(file_name.c_str());
8191  if ( !is.good() ) {
8192  return false;
8193  }
8194  return Read(is);
8195 }
8196 
8197 
8198 // Parse string for CDiagErrCodeInfo::Read()
8199 
8201  const SIZE_TYPE line,
8202  int& x_code,
8203  int& x_severity,
8204  string& x_message,
8205  bool& x_ready)
8206 {
8207  list<string> tokens; // List with line tokens
8208 
8209  try {
8210  // Get message text
8211  SIZE_TYPE pos = str.find_first_of(':');
8212  if (pos == NPOS) {
8213  x_message = kEmptyStr;
8214  } else {
8215  x_message = NStr::TruncateSpaces(str.substr(pos+1));
8216  str.erase(pos);
8217  }
8218 
8219  // Split string on parts
8220  NStr::Split(str, ",", tokens,
8222  if (tokens.size() < 2) {
8223  ERR_POST_X(11, "Error message file parsing: Incorrect file format "
8224  ", line " + NStr::UInt8ToString(line));
8225  return false;
8226  }
8227  // Mnemonic name (skip)
8228  tokens.pop_front();
8229 
8230  // Error code
8231  string token = NStr::TruncateSpaces(tokens.front());
8232  tokens.pop_front();
8233  x_code = NStr::StringToInt(token);
8234 
8235  // Severity
8236  if ( !tokens.empty() ) {
8237  token = NStr::TruncateSpaces(tokens.front());
8238  EDiagSev sev;
8239  if (CNcbiDiag::StrToSeverityLevel(token.c_str(), sev)) {
8240  x_severity = sev;
8241  } else {
8242  ERR_POST_X(12, Warning << "Error message file parsing: "
8243  "Incorrect severity level in the verbose "
8244  "message file, line " + NStr::UInt8ToString(line));
8245  }
8246  } else {
8247  x_severity = -1;
8248  }
8249  }
8250  catch (const CException& e) {
8251  ERR_POST_X(13, Warning << "Error message file parsing: " << e.GetMsg() <<
8252  ", line " + NStr::UInt8ToString(line));
8253  return false;
8254  }
8255  x_ready = true;
8256  return true;
8257 }
8258 
8259 
8261 {
8262  string str; // The line being parsed
8263  SIZE_TYPE line; // # of the line being parsed
8264  bool err_ready = false; // Error data ready flag
8265  int err_code = 0; // First level error code
8266  int err_subcode = 0; // Second level error code
8267  string err_message; // Short message
8268  string err_text; // Error explanation
8269  int err_severity = -1; // Use default severity if
8270  // has not specified
8271  int err_subseverity = -1; // Use parents severity if
8272  // has not specified
8273 
8274  for (line = 1; NcbiGetlineEOL(is, str); line++) {
8275 
8276  // This is a comment or empty line
8277  if (!str.length() || NStr::StartsWith(str,"#")) {
8278  continue;
8279  }
8280  // Add error description
8281  if (err_ready && str[0] == '$') {
8282  if (err_subseverity == -1)
8283  err_subseverity = err_severity;
8284  SetDescription(ErrCode(err_code, err_subcode),
8285  SDiagErrCodeDescription(err_message, err_text,
8286  err_subseverity));
8287  // Clean
8288  err_subseverity = -1;
8289  err_text = kEmptyStr;
8290  err_ready = false;
8291  }
8292 
8293  // Get error code
8294  if (NStr::StartsWith(str,"$$")) {
8295  if (!s_ParseErrCodeInfoStr(str, line, err_code, err_severity,
8296  err_message, err_ready))
8297  continue;
8298  err_subcode = 0;
8299 
8300  } else if (NStr::StartsWith(str,"$^")) {
8301  // Get error subcode
8302  s_ParseErrCodeInfoStr(str, line, err_subcode, err_subseverity,
8303  err_message, err_ready);
8304 
8305  } else if (err_ready) {
8306  // Get line of explanation message
8307  if (!err_text.empty()) {
8308  err_text += '\n';
8309  }
8310  err_text += str;
8311  }
8312  }
8313  if (err_ready) {
8314  if (err_subseverity == -1)
8315  err_subseverity = err_severity;
8316  SetDescription(ErrCode(err_code, err_subcode),
8317  SDiagErrCodeDescription(err_message, err_text, err_subseverity));
8318  }
8319  return true;
8320 }
8321 
8322 
8324  SDiagErrCodeDescription* description)
8325  const
8326 {
8327  // Find entry
8328  TInfo::const_iterator find_entry = m_Info.find(err_code);
8329  if (find_entry == m_Info.end()) {
8330  return false;
8331  }
8332  // Get entry value
8333  const SDiagErrCodeDescription& entry = find_entry->second;
8334  if (description) {
8335  *description = entry;
8336  }
8337  return true;
8338 }
8339 
8340 
8341 const char* g_DiagUnknownFunction(void)
8342 {
8343  return kEmptyCStr;
8344 }
8345 
8346 
8348  double timespan,
8350 {
8352  CDiagContext_Extra perf(status, timespan, args);
8354  perf.Print("ncbi_phid", rctx.GetHitID());
8355  }
8356  return perf;
8357 }
8358 
8359 
8360 void EndmFatal(const CNcbiDiag& diag)
8361 {
8362  Endm(diag);
8363  Abort();
8364 }
8365 
8366 
ncbi::TMaskedQueryRegions mask
const char * kWebDirToPort
Definition: cgiapp.cpp:1590
const char * kToolkitRcPath
Definition: cgiapp.cpp:1589
CAtomicCounter m_MsgsInQueue
Definition: ncbidiag.cpp:7187
CFastMutex m_QueueLock
Definition: ncbidiag.cpp:7189
CSemaphore m_DequeueSem
Definition: ncbidiag.cpp:7195
CAsyncDiagThread(const string &thread_suffix)
Definition: ncbidiag.cpp:7310
void Stop(void)
Definition: ncbidiag.cpp:7510
deque< SAsyncDiagMessage > m_MsgQueue
Definition: ncbidiag.cpp:7197
virtual ~CAsyncDiagThread(void)
Definition: ncbidiag.cpp:7323
CDiagHandler * m_SubHandler
Definition: ncbidiag.cpp:7188
virtual void * Main(void)
Derived (user-created) class must provide a real thread function.
Definition: ncbidiag.cpp:7393
CSemaphore m_QueueSem
Definition: ncbidiag.cpp:7194
string m_ThreadSuffix
Definition: ncbidiag.cpp:7198
CAtomicCounter –.
Definition: ncbicntr.hpp:71
CCompatDiagHandler(FDiagHandler func, void *data, FDiagCleanup cleanup)
Definition: ncbidiag.cpp:8031
FDiagHandler m_Func
Definition: ncbidiag.cpp:8043
virtual void Post(const SDiagMessage &mess)
Post message to handler.
Definition: ncbidiag.cpp:8040
FDiagCleanup m_Cleanup
Definition: ncbidiag.cpp:8045
CCompatStreamDiagHandler(CNcbiOstream *os, bool quick_flush=true, FDiagCleanup cleanup=0, void *cleanup_data=0, const string &stream_name=kEmptyStr)
Definition: ncbidiag.cpp:8060
CCoreException –.
Definition: ncbiexpt.hpp:1476
Guard for collecting diag messages (affects the current thread only).
Definition: ncbidiag.hpp:1300
Incapsulate compile time information such as __FILE__, __LINE__, NCBI_MODULE, current function.
Definition: ncbidiag.hpp:65
Thread local context data stored in TLS.
Definition: ncbidiag.cpp:447
CDiagContextThreadData(const CDiagContextThreadData &)
CStopWatch * GetOrCreateStopWatch(void)
Get request timer, create if not exist yet.
Definition: ncbidiag.cpp:466
CDiagCollectGuard * GetCollectGuard(void)
Definition: ncbidiag.cpp:1159
TCount GetRequestId(void)
Request id.
Definition: ncbidiag.cpp:1177
TCollectGuards m_CollectGuards
Definition: ncbidiag.cpp:507
void SetRequestId(TCount id)
Definition: ncbidiag.cpp:1183
void CollectDiagMessage(const SDiagMessage &mess)
Definition: ncbidiag.cpp:1165
void AddCollectGuard(CDiagCollectGuard *guard)
Definition: ncbidiag.cpp:1088
SDiagMessage::TCount TCount
Definition: ncbidiag.cpp:458
TTID GetTID(void) const
Get cached thread ID.
Definition: ncbidiag.cpp:482
CRef< CRequestContext > m_DefaultRequestCtx
Definition: ncbidiag.cpp:511
Uint8 TTID
Thread ID.
Definition: ncbidiag.cpp:479
TCount GetThreadPostNumber(EPostNumberIncrement inc)
Get thread post number.
Definition: ncbidiag.cpp:1081
CStopWatch * GetStopWatch(void)
Get request timer or null.
Definition: ncbidiag.cpp:468
static CDiagContextThreadData & GetThreadData(void)
Get diag context data for the current thread.
Definition: ncbidiag.cpp:956
list< SDiagMessage > TDiagCollection
Definition: ncbidiag.cpp:502
void SetRequestContext(CRequestContext *ctx)
Set request context.
Definition: ncbidiag.cpp:1043
CRequestContext & GetRequestContext(void)
Get current request context.
Definition: ncbidiag.cpp:1034
CRef< CRequestContext > m_RequestCtx
Definition: ncbidiag.cpp:510
void ResetStopWatch(void)
Delete request timer.
Definition: ncbidiag.cpp:470
CDiagBuffer & GetDiagBuffer(void)
Diag buffer.
Definition: ncbidiag.cpp:473
CDiagContextThreadData & operator=(const CDiagContextThreadData &)
unique_ptr< CDiagBuffer > m_DiagBuffer
Definition: ncbidiag.cpp:504
list< CDiagCollectGuard * > TCollectGuards
Definition: ncbidiag.cpp:499
void RemoveCollectGuard(CDiagCollectGuard *guard)
Definition: ncbidiag.cpp:1094
TDiagCollection m_DiagCollection
Definition: ncbidiag.cpp:508
Temporary object for holding extra message arguments.
Definition: ncbidiag.hpp:1828
CDiagErrCodeInfo –.
Definition: ncbidiag.hpp:3029
CDiagFileHandleHolder(const string &fname, CDiagHandler::TReopenFlags flags)
Definition: ncbidiag.cpp:6453
virtual ~CDiagFileHandleHolder(void)
Definition: ncbidiag.cpp:6480
ELockType m_LockType
Definition: ncbidiag.cpp:171
CDiagLock(ELockType locktype)
Definition: ncbidiag.cpp:130
~CDiagLock(void)
Definition: ncbidiag.cpp:154
bool m_UsedRWLock
Definition: ncbidiag.cpp:170
CDiagRecycler(void)
Definition: ncbidiag.cpp:858
~CDiagRecycler(void)
Definition: ncbidiag.cpp:866
CDirEntry –.
Definition: ncbifile.hpp:262
CDir –.
Definition: ncbifile.hpp:1695
CEncodedString –.
Definition: ncbistr.hpp:4823
virtual string Decode(const CTempString src, EStringType stype) const
Decode the string.
Definition: ncbidiag.cpp:4796
bool m_AllowBadNames
Definition: ncbidiag.cpp:5418
CExtraEncoder(bool allow_bad_names=false)
Definition: ncbidiag.cpp:5413
virtual string Encode(const CTempString src, EStringType stype) const
Encode the string.
Definition: ncbidiag.cpp:5422
CFastLocalTime –.
Definition: ncbitime.hpp:1895
CFastMutex –.
Definition: ncbimtx.hpp:667
CFileDiagHandler –.
Definition: ncbidiag.hpp:2698
CFileHandleDiagHandler –.
Definition: ncbidiag.hpp:2634
CFile –.
Definition: ncbifile.hpp:1604
void Guard(resource_type &resource)
Manually force the guard to protect some other resource.
Definition: guard.hpp:175
void Release()
Manually force the resource to be released.
Definition: guard.hpp:166
unsigned int TValue
Definition: ncbidiag.cpp:301
CLogRateLimit(void)
Definition: ncbidiag.cpp:302
CLogRateLimit(TValue val)
Definition: ncbidiag.cpp:303
void Set(TValue val)
Definition: ncbidiag.cpp:310
TValue m_Value
Definition: ncbidiag.cpp:316
static CNcbiApplication * Instance(void)
Singleton method.
Definition: ncbiapp.cpp:264
CNcbiDiag –.
Definition: ncbidiag.hpp:924
CNcbiEnvironment –.
Definition: ncbienv.hpp:110
CNcbiLogFields –.
Definition: ncbidiag.hpp:2397
CNcbiOstrstreamToString class helps convert CNcbiOstrstream to a string Sample usage:
Definition: ncbistre.hpp:802
CNcbiRegistry –.
Definition: ncbireg.hpp:913
CObject –.
Definition: ncbiobj.hpp:180
~CRecursionGuard(void)
Definition: ncbidiag.cpp:4255
CRecursionGuard(bool &flag)
Definition: ncbidiag.cpp:4254
CRequestRateControl –.
CSafeStaticLifeSpan::
CSafeStatic<>::
T & Get(void)
Create the variable if not created yet, return the reference.
CSemaphore –.
Definition: ncbimtx.hpp:1375
Helper class to hold hit id and sub-hit counter which can be shared between multiple request contexts...
Definition: request_ctx.hpp:65
CSpinLock –.
Definition: ncbimtx.hpp:843
bool Empty(void) const
Check if stack trace information is available.
Definition: ncbi_stack.hpp:90
void SetPrefix(const string &prefix) const
Set new prefix.
Definition: ncbi_stack.hpp:105
CStopWatch –.
Definition: ncbitime.hpp:1937
CStreamDiagHandler_Base –.
Definition: ncbidiag.hpp:2574
CStreamDiagHandler –.
Definition: ncbidiag.hpp:2596
CStringException –.
Definition: ncbistr.hpp:4506
Template for parsing string into pairs of name and value or merging them back into a single string.
Definition: ncbistr.hpp:4594
static string GetUserName(void)
Get actual user name for the current process.
AutoPtr< CDiagHandler > m_OrigHandler
Definition: ncbidiag.cpp:231
virtual void PostToConsole(const SDiagMessage &mess)
Post message to console regardless of its severity.
Definition: ncbidiag.cpp:204
CDiagHandler * GetOriginalHandler(void) const
Definition: ncbidiag.cpp:224
virtual void Post(const SDiagMessage &mess)
Post message to handler.
Definition: ncbidiag.cpp:6262
EDiagSev m_MinSev
Definition: ncbidiag.cpp:230
virtual void Reopen(TReopenFlags flags)
Reopen file to enable log rotation.
Definition: ncbidiag.cpp:217
virtual string GetLogName(void)
Get current diag posts destination.
Definition: ncbidiag.cpp:212
CTeeDiagHandler(CDiagHandler *orig, bool own_orig)
Definition: ncbidiag.cpp:6246
CTempString implements a light-weight string on top of a storage buffer whose lifetime management is ...
Definition: tempstr.hpp:65
CTimeException –.
Definition: ncbitime.hpp:2075
CTimeSpan.
Definition: ncbitime.hpp:1313
CTime –.
Definition: ncbitime.hpp:296
CVersionInfo –.
ErrCode –.
Definition: ncbidiag.hpp:815
Callback interface for stream parser.
Definition: ncbidiag.hpp:1575
CStringPairsParser –.
Definition: ncbistr.hpp:4534
Encoder interface. Names and values can be encoded with different rules.
Definition: ncbistr.hpp:4550
void erase(iterator pos)
Definition: map.hpp:167
container_type::const_iterator const_iterator
Definition: map.hpp:53
const_iterator end() const
Definition: map.hpp:152
const_iterator find(const key_type &key) const
Definition: map.hpp:153
void(*)(CSeq_entry_Handle seh, IWorkbench *wb, const CSerialObject &obj) handler
void Print(const CCompactSAMApplication::AlignInfo &ai)
Define CVersionInfo, a version info storage class.
static uch flags
static ush * file_type
static const char ip[]
Definition: des.c:75
const char * file_name[]
std::ofstream out("events_result.xml")
main entry point for tests
static void cleanup(void)
Definition: ct_dynamic.c:30
CS_CONTEXT * ctx
Definition: t0006.c:12
static int err_handler(DBPROCESS *dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
#define false
Definition: bool.h:36
static const char * str(char *buf, int n)
Definition: stats.c:84
static HENV env
Definition: transaction2.c:38
static char tmp[3200]
Definition: utf8.c:42
char data[12]
Definition: iconv.c:80
static bool trace
void reset(element_type *p=0, EOwnership ownership=eTakeOwnership)
Reset will delete the old pointer (if owned), set content to the new value, and assume the ownership ...
Definition: ncbimisc.hpp:480
static string GetAppName(EAppNameType name_type=eBaseName, int argc=0, const char *const *argv=NULL)
Definition: ncbiapp.cpp:1377
const CNcbiEnvironment & GetEnvironment(void) const
Get the application's cached environment.
const string & GetProgramExecutablePath(EFollowLinks follow_links=eIgnoreLinks) const
Get the application's executable path.
static CNcbiApplicationGuard InstanceGuard(void)
Singleton method.
Definition: ncbiapp.cpp:133
const CNcbiRegistry & GetConfig(void) const
Get the application's cached configuration parameters (read-only).
#define ITERATE(Type, Var, Cont)
ITERATE macro to sequence through container elements.
Definition: ncbimisc.hpp:815
element_type * get(void) const
Get pointer.
Definition: ncbimisc.hpp:469
const string & GetProgramDisplayName(void) const
Get the application's "display" name.
#define NON_CONST_ITERATE(Type, Var, Cont)
Non constant version of ITERATE macro.
Definition: ncbimisc.hpp:822
const CVersionAPI & GetFullVersion(void) const
Get the program version information.
Definition: ncbiapp.cpp:1189
@ eTakeOwnership
An object can take ownership of another.
Definition: ncbi_types.h:136
@ eNoOwnership
No ownership is assumed.
Definition: ncbi_types.h:135
string
Definition: cgiapp.hpp:687
#define NULL
Definition: ncbistd.hpp:225
void Set(TValue new_value) THROWS_NONE
Set atomic counter value.
Definition: ncbicntr.hpp:185
TValue Add(int delta) THROWS_NONE
Atomically add value (=delta), and return new counter value.
Definition: ncbicntr.hpp:278
TValue Get(void) const THROWS_NONE
Get atomic counter value.
Definition: ncbicntr.hpp:168
#define _TRACE_X(err_subcode, message)
Definition: ncbidbg.hpp:125
EValidateAction xncbi_GetValidateAction(void)
Get the action to be performed.
Definition: ncbidbg.cpp:65
#define _DEBUG_ARG(arg)
Definition: ncbidbg.hpp:134
@ eValidate_Throw
Throw an exception if not valid.
Definition: ncbidbg.hpp:176
bool x_IsSetOldFormat(void) const
Definition: ncbidiag.cpp:5348
int m_ErrCode
Error code.
Definition: ncbidiag.hpp:1659
int m_ErrSubCode
Sub Error code.
Definition: ncbidiag.hpp:1660
TFields m_Fields
Definition: ncbidiag.hpp:2423
TDiagPostFlags GetPostFlags(void) const
Get post flags for the current message.
virtual ~CAsyncDiagHandler(void)
Definition: ncbidiag.cpp:7213
string m_Explanation
Error message (with detailed explanation)
Definition: ncbidiag.hpp:3014
void Write(string &str, TDiagWriteFlags flags=fNone) const
Binary OR of "EDiagWriteFlags".
Definition: ncbidiag.cpp:5355
EFormatFlag m_Format
Definition: ncbidiag.hpp:1753
void Release(void)
Release the guard.
Definition: ncbidiag.cpp:575
void SetDiagFilter(EDiagFilter what, const char *filter_str)
Set diagnostic filter.
Definition: ncbidiag.cpp:7670
TExtraArgs m_ExtraArgs
If event type is "extra", contains the list of arguments.
Definition: ncbidiag.hpp:1678
void PushDiagPostPrefix(const char *prefix)
Push a string to the list of message prefixes.
Definition: ncbidiag.cpp:6109
static string SelectLastHitID(const string &hit_ids)
Select the last hit id from the list of ids separated with commas and optional spaces.
void SetAutoWrite(bool value)
Set AutoWrite flag.
Definition: ncbidiag.cpp:1913
void PrintRequestStop(void)
Print request stop message (for request-driven applications)
Definition: ncbidiag.cpp:2778
CDiagContext_Extra & Print(const string &name, const string &value)
The method does not print the argument, but adds it to the string.
Definition: ncbidiag.cpp:2622
void UnsetRequestStatus(void)
CDiagContext_Extra PrintRequestStart(void)
Create a temporary CDiagContext_Extra object.
Definition: ncbidiag.cpp:2162
CDiagContext_Extra & AllowBadSymbolsInArgNames(void)
Allow bad symbols in argument names.
Definition: ncbidiag.cpp:2213
void x_InitData(void) const
Definition: ncbidiag.cpp:5915
void ParseCurrFunctName(void) const
Definition: logging.cpp:1339
void SetCollectSeverity(EDiagSev sev)
Set new collect severity.
Definition: ncbidiag.cpp:597
const char * GetModule(void) const
Get module name of the current message.
void SetDescription(const ErrCode &err_code, const SDiagErrCodeDescription &description)
Set error description for specified error code.
string m_PostPrefix
Message prefix.
Definition: ncbidiag.hpp:2970
string GetSessionID(void) const
Get the effective session id: the per-request session id if set, or the default session id.
Definition: ncbidiag.cpp:2903
TCount m_RequestId
FastCGI iteration or request ID.
Definition: ncbidiag.hpp:1669
EDiagPostFlag
Which parts of the diagnostic context should be posted.
Definition: ncbidiag.hpp:692
void SetBytesWr(Int8 bytes)
EDiagSev GetDiagPostLevel(void)
Get current threshold severity for posting the messages.
Definition: ncbidiag.cpp:6151
~CDiagCollectGuard(void)
Destroy the guard, return post level to the one set before the guard initialization.
Definition: ncbidiag.cpp:569
void SetDiagPostFlag(EDiagPostFlag flag)
Set the specified flag (globally).
Definition: ncbidiag.cpp:6070
static const char * kProperty_UserName
Global properties.
Definition: ncbidiag.hpp:2052
EDiagSevChange
Severity level change state.
Definition: ncbidiag.hpp:666
EDiagSev m_SeverityCap
Definition: ncbidiag.hpp:1383
bool m_AllowBadExtraNames
Definition: ncbidiag.hpp:1758
static string GetEventName(EEventType event)
Definition: ncbidiag.cpp:5315
unique_ptr< CEncodedString > m_Username
Definition: ncbidiag.hpp:2357
static TPID sm_PID
Definition: ncbidiag.hpp:2352
CStreamDiagHandler_Base * m_Perf
Definition: ncbidiag.hpp:2780
bool ParseMessage(const string &message)
Parse the whole string into the message.
Definition: ncbidiag.cpp:4879
string m_StrCurrFunctName
Definition: ncbidiag.hpp:122
static bool IsSetOldPostFormat(void)
Check old/new format flag (for compatibility only)
Definition: ncbidiag.cpp:3346
#define ERR_POST_ONCE(message)
Error posting only once during program execution.
Definition: ncbidiag.hpp:602
const char * m_File
File name.
Definition: ncbidiag.hpp:1654
EDiagSev m_PostSeverity
Post severity.
Definition: ncbidiag.hpp:2973
Uint8 TCount
Generic type for counters (posts, requests etc.)
Definition: ncbidiag.hpp:1605
TTID m_TID
Thread ID.
Definition: ncbidiag.hpp:1666
const char * m_Buffer
Not guaranteed to be '\0'-terminated!
Definition: ncbidiag.hpp:1652
void SetModule(const string &module)
Definition: ncbidiag.cpp:729
void PrintStart(const string &message)
Print start/stop etc.
Definition: ncbidiag.cpp:2095
const string & GetHost(void) const
Get host name.
Definition: ncbidiag.cpp:1766
static void s_UnescapeNewlines(string &buf)
Definition: ncbidiag.cpp:5515
CStreamDiagHandler_Base * m_Trace
Definition: ncbidiag.hpp:2778
const CNcbiDiag & SetClass(const char *nclass) const
Set class name.
Definition: ncbidiag.cpp:7760
CNcbiOstream * m_Stream
Diagnostic stream.
Definition: ncbidiag.hpp:2615
EDiagSev m_CollectSev
Definition: ncbidiag.hpp:1382
const string & GetEncodedHostname(void) const
Get URL-encoded hostname.
Definition: ncbidiag.cpp:1832
EDiagAppState GetGlobalAppState(void) const
Always returns global application state.
Definition: ncbidiag.cpp:2796
string GetEncodedSessionID(void) const
Get url-encoded session id.
Definition: logging.cpp:874
void SetLine(int line)
Definition: ncbidiag.cpp:736
string GetStringUID(TUID uid=0) const
Return string representation of UID.
Definition: ncbidiag.cpp:1691
CDiagContext & GetDiagContext(void)
Get diag context instance.
Definition: ncbidiag.cpp:3874
void(* FAbortHandler)(void)
Abort handler function type.
Definition: ncbidiag.hpp:1524
void SetAppState(EDiagAppState state)
bool GetAutoIncRequestIDOnPost(void) const
Get auto-increment state.
bool x_ParseExtraArgs(const string &str, size_t pos)
Definition: ncbidiag.cpp:4843
static void SetRequestContext(CRequestContext *ctx)
Shortcut to CDiagContextThreadData::GetThreadData().SetRequestContext()
Definition: ncbidiag.cpp:1907
virtual void Reopen(TReopenFlags flags)
Reopen file to enable log rotation.
Definition: ncbidiag.cpp:6522
void SetAppState(EDiagAppState state)
Set application state.
Definition: ncbidiag.cpp:2815
const char * m_Module
Definition: ncbidiag.hpp:110
void x_Match(const string &name, const string &value, CDiagContext_Extra &extra) const
Definition: ncbidiag.cpp:3921
void SetDiagFixedPostLevel(const EDiagSev post_sev)
Sets and locks the level, combining the previous two calls.
Definition: ncbidiag.cpp:6179
CNcbiOstream * GetLogStream(EDiagFileType file_type)
Get current log stream.
Definition: ncbidiag.cpp:6993
void SetAction(EAction action)
Specify on-destroy action.
Definition: ncbidiag.hpp:1362
void SetPrintSeverity(EDiagSev sev)
Set new print severity.
Definition: ncbidiag.cpp:589
Uint8 GetStartingPoint(void) const
Get the lowest thread-local post number in this guard's scope.
Definition: ncbidiag.hpp:1365
void SetSplitLogFile(bool value)
Split log files flag.
Definition: ncbidiag.cpp:6705
virtual void WriteMessage(const char *buf, size_t len, EDiagFileType file_type)
Write string to the log.
Definition: ncbidiag.cpp:6396
EDiagCollectMessages
Flags to control collecting messages and flushing them to the new destination when switching diag han...
Definition: ncbidiag.hpp:1798
TExtraArgs * m_Args
Definition: ncbidiag.hpp:1919
static bool UpdatePID(void)
Reset PID cache (e.g. after fork). Return true if PID was updated.
Definition: logging.cpp:830
list< string > TFields
Definition: ncbidiag.hpp:2420
const char * m_Module
Module name.
Definition: ncbidiag.hpp:1655
static const char * kProperty_AppName
Definition: ncbidiag.hpp:2055
virtual void Reopen(TReopenFlags flags)
Reopen file to enable log rotation.
Definition: ncbidiag.cpp:7261
virtual string ComposeMessage(const SDiagMessage &msg, EDiagFileType *file_type) const
Compose message without writing it.
Definition: ncbidiag.cpp:6389
static const char * kProperty_ClientIP
Definition: ncbidiag.hpp:2060
CDiagContext_Extra & PrintNcbiRoleAndLocation(void)
Definition: ncbidiag.cpp:2224
const string & GetHost(void) const
Access to strings stored in SDiagMessageData.
Definition: ncbidiag.cpp:5968
static bool sm_ApplogSeverityLocked
Definition: ncbidiag.hpp:2374
size_t m_MaxMessages
Definition: ncbidiag.hpp:2370
bool m_TraceEnabled
Trace enabled?
Definition: ncbidiag.hpp:2978
~CDiagRestorer(void)
Restores captured settings.
Definition: ncbidiag.cpp:8004
string GetSessionID(void) const
Session ID.
const string & GetHostname(void) const
Get cached hostname - do not try to detect host name as GetHost() does.
Definition: ncbidiag.cpp:1826
void DiagHandler_Reopen(void)
Ask diagnostic handler to reopen log files if necessary.
Definition: ncbidiag.cpp:6344
string GetDiagFilter(EDiagFilter what)
Get current diagnostic filter.
Definition: ncbidiag.cpp:7681
virtual void PostToConsole(const SDiagMessage &mess)
Post message to console regardless of its severity.
Definition: ncbidiag.cpp:6359
int GetExitSignal(void) const
Get exit signal.
Definition: ncbidiag.hpp:2183
void SetLogRate_Limit(ELogRate_Type type, unsigned int limit)
Definition: ncbidiag.cpp:1380
virtual void Reopen(TReopenFlags)
Reopen file to enable log rotation.
Definition: ncbidiag.hpp:2480
unique_ptr< CRequestRateControl > m_TraceLogRC
Definition: ncbidiag.hpp:2379
string GetLogFile(EDiagFileType file_type) const
Get current log file name.
Definition: ncbidiag.cpp:6975
void SetRequestID(TCount rid)
Set request ID.
CAsyncDiagThread * m_AsyncThread
Thread handling all physical printing of log messages.
Definition: ncbidiag.hpp:2831
void SetSessionID(const string &session)
SDiagMessage(EDiagSev severity, const char *buf, size_t len, const char *file=0, size_t line=0, TDiagPostFlags flags=eDPF_Default, const char *prefix=0, int err_code=0, int err_subcode=0, const char *err_text=0, const char *module=0, const char *nclass=0, const char *function=0)
Initialize SDiagMessage fields.
Definition: ncbidiag.cpp:4486
atomic< bool > m_ErrLogSuspended
Definition: ncbidiag.hpp:2381
CDiagContext_Extra Extra(void) const
Create a temporary CDiagContext_Extra object.
Definition: ncbidiag.hpp:2095
void x_Release(void)
Definition: ncbidiag.cpp:2408
#define DIAG_COMPILE_INFO
Make compile time diagnostic information object to use in CNcbiDiag and CException.
Definition: ncbidiag.hpp:170
list< SDiagMessage > TMessages
Definition: ncbidiag.hpp:2349
TCount m_ProcPost
Number of the post in the process.
Definition: ncbidiag.hpp:1667
bool DisableDiagPostLevelChange(bool disable_change)
Disable change the diagnostic post level.
Definition: ncbidiag.cpp:6186
void x_CreateUID_AsyncSafe(void) const
Definition: ncbidiag.cpp:1634
bool IsSetRequestStatus(void) const
string m_StrModule
Definition: ncbidiag.hpp:121
Uint8 TPID
Process ID.
Definition: ncbidiag.hpp:1600
void SetSubHandler(CStreamDiagHandler_Base *handler, EDiagFileType file_type, bool own)
Definition: ncbidiag.cpp:7016
size_t m_Line
Line number in file.
Definition: ncbidiag.hpp:1658
void SetLogName(const string &log_name)
Definition: ncbidiag.cpp:6414
void SetHostname(const string &hostname)
Set hostname.
Definition: ncbidiag.cpp:1838
void SetDiagRequestId(Uint8 id)
Set iteration number/request ID.
Definition: ncbidiag.cpp:1201
TUID GetUID(void) const
Return (create if not created yet) unique diagnostic ID.
Definition: ncbidiag.cpp:1664
CDiagBuffer & m_Buffer
This thread's error msg. buffer.
Definition: ncbidiag.hpp:1210
TUID GetUID(void) const
Get UID from current context or parsed from a string.
Definition: ncbidiag.cpp:5335
#define ERR_POST_X_ONCE(err_subcode, message)
Error posting only once during program execution with default error code and given error subcode.
Definition: ncbidiag.hpp:621
void SetClientIP(const string &client)
static TTID GetTID(void)
Definition: ncbidiag.cpp:3862
static const char * kProperty_ExitSig
Definition: ncbidiag.hpp:2056
bool CheckFilters(const CException *ex=NULL) const
Check if filters are passed for the current message.
Definition: ncbidiag.cpp:7774
bool m_AppNameSet
Definition: ncbidiag.hpp:2359
~CDiagCompileInfo(void)
Definition: logging.cpp:1332
void x_Init(EDiagSev print_severity, EDiagSev collect_severity, EAction action)
Definition: ncbidiag.cpp:538
bool m_CanDeleteErrCodeInfo
Can delete err code info?
Definition: ncbidiag.hpp:2982
virtual void SetLogName(const string &log_name)
Definition: ncbidiag.cpp:6512
void x_SaveContextData(void) const
Definition: ncbidiag.cpp:5951
int TDiagPostFlags
Binary OR of "EDiagPostFlag".
Definition: ncbidiag.hpp:785
string x_GetNextHitID(bool is_default) const
Definition: ncbidiag.cpp:1721
string FormatExtraMessage(void) const
Convert extra arguments to string.
Definition: ncbidiag.cpp:5485
EDiagSev m_Severity
Severity level.
Definition: ncbidiag.hpp:1651
static void x_StartRequest(void)
Definition: ncbidiag.cpp:3197
bool GetSplitLogFile(void)
Get split log files flag.
Definition: ncbidiag.cpp:6711
~CNcbiDiag(void)
Destructor.
Definition: ncbidiag.cpp:7732
bool m_QuickFlush
Quick flush of stream flag.
Definition: ncbidiag.hpp:2618
unique_ptr< TMessages > m_Messages
Definition: ncbidiag.hpp:2683
bool GetOmitStackTrace(void) const
Definition: ncbidiag.hpp:1199
static string SelectLastSessionID(const string &session_ids)
Select the last session id from the list of ids separated with commas and optional spaces,...
unique_ptr< CEncodedString > m_Host
Definition: ncbidiag.hpp:2355
EAppDiagStream
Where to write the application's diagnostics to.
Definition: ncbidiag.hpp:1780
EDiagTrace m_TraceDefault
Default trace setting.
Definition: ncbidiag.hpp:2977
Uint8 TTID
Get thread ID used in messages.
Definition: ncbidiag.hpp:2272
void PrintExtra(const string &message)
Print extra message in plain text format.
Definition: ncbidiag.cpp:2156
static bool UpdatePID_AsyncSafe(void)
Definition: ncbidiag.cpp:1555
bool x_IsSetDefaultHitID(void) const
Definition: ncbidiag.cpp:2990
void UnsetDiagTraceFlag(EDiagPostFlag flag)
Definition: ncbidiag.cpp:6091
virtual string ComposeMessage(const SDiagMessage &msg, EDiagFileType *file_type) const
Compose message without writing it.
Definition: ncbidiag.cpp:6667
EPostNumberIncrement
Post number increment flag for GetProcessPostNumber() and GetThreadPostNumber().
Definition: ncbidiag.hpp:1811
const char * m_Prefix
Prefix string.
Definition: ncbidiag.hpp:1662
virtual void Post(const SDiagMessage &mess)=0
Post message to handler.
bool x_DiagAtApplicationLevel(void) const
Definition: ncbidiag.cpp:2959
string GetDefaultHitID(void) const
Get global default hit id.
Definition: ncbidiag.cpp:1748
EDiagSev GetDiagDieLevel(void)
Get the "die" (abort) level for the program.
Definition: ncbidiag.cpp:6211
static void s_EscapeNewlines(string &buf)
Definition: ncbidiag.cpp:5496
bool GetDescription(const ErrCode &err_code, SDiagErrCodeDescription *description) const
Get description for specified error code.
Definition: ncbidiag.cpp:8323
void DeleteProperty(const string &name, EPropertyMode mode=eProp_Default)
Delete a property by name.
Definition: ncbidiag.cpp:2073
string m_Message
Error message (short)
Definition: ncbidiag.hpp:3013
~CDiagContext_Extra(void)
Prints all arguments as "name1=value1&name2=value2...".
Definition: ncbidiag.cpp:2436
#define DIAG_POST_LEVEL
Diagnostic post severity level.
Definition: ncbidiag.hpp:1447
CDiagContext_Extra & operator=(const CDiagContext_Extra &args)
Definition: ncbidiag.cpp:2419
virtual string ComposeMessage(const SDiagMessage &msg, EDiagFileType *file_type) const
Compose message without writing it.
Definition: ncbidiag.cpp:7131
void PushMessage(const SDiagMessage &message)
Save new message.
Definition: ncbidiag.cpp:3379
bool IsDiagStream(const CNcbiOstream *os)
Definition: ncbidiag.cpp:7636
size_t GetLine(void) const
Get line number for the current message.
const string & GetEncodedAppName(void) const
Get URL-encoded application name.
Definition: ncbidiag.cpp:1875
SDiagErrCodeDescription(void)
Constructor.
Definition: ncbidiag.cpp:8179
TProperties m_Properties
Definition: ncbidiag.hpp:2367
bool IsVisibleDiagPostLevel(EDiagSev sev)
Check if the specified severity is higher or equal to the currently selected post level and will be p...
Definition: ncbidiag.cpp:6166
EEventType
Type of event to report.
Definition: ncbidiag.hpp:1640
void FlushMessages(CDiagHandler &handler)
Flush the collected messages to the current diag handler.
Definition: ncbidiag.cpp:3387
TDiagPostFlags m_Flags
Bitwise OR of "EDiagPostFlag".
Definition: ncbidiag.hpp:1661
bool m_NoTee
Special flag indicating that the message should not be printed by Tee-handler.
Definition: ncbidiag.hpp:1685
static CDiagContext * sm_Instance
Definition: ncbidiag.hpp:2371
EDiagSev m_DieSeverity
Die level severity.
Definition: ncbidiag.hpp:2976
static CRequestContext & GetRequestContext(void)
Shortcut to CDiagContextThreadData::GetThreadData().GetRequestContext()
Definition: ncbidiag.cpp:1901
atomic< bool > m_AppLogSuspended
Definition: ncbidiag.hpp:2380
TCount GetRequestID(void) const
Get request ID (or zero if not set).
void PopDiagPostPrefix(void)
Pop a string from the list of message prefixes.
Definition: ncbidiag.cpp:6119
EDiagAppState m_AppState
Definition: ncbidiag.hpp:2366
void AppendDiagFilter(EDiagFilter what, const char *filter_str)
Append diagnostic filter.
Definition: ncbidiag.cpp:7694
static void DiagTrouble(const CDiagCompileInfo &info, const char *message=NULL)
Display trouble error message.
Definition: ncbidiag.cpp:7938
void SetAppName(const string &app_name)
Set application name.
Definition: ncbidiag.cpp:1884
static const char * kProperty_ReqTime
Definition: ncbidiag.hpp:2063
bool GetDiagTrace(void)
Check if traces are enabled.
Definition: ncbidiag.cpp:6240
void DiscardMessages(void)
Discard the collected messages without printing them.
Definition: ncbidiag.cpp:3411
string GetClientIP(void) const
Client IP/hostname.
static TCount GetThreadPostNumber(EPostNumberIncrement inc)
Return thread post number (incrementing depends on the flag).
Definition: ncbidiag.cpp:3856
CStopWatch * m_ReopenTimer
Definition: ncbidiag.hpp:2679
static bool GetLogTruncate(void)
Get log file truncation flag.
Definition: ncbidiag.cpp:3469
static void SetApplogSeverityLocked(bool lock)
Definition: ncbidiag.hpp:2298
static TPID GetPID(void)
Get cached PID (read real PID if not cached yet).
Definition: ncbidiag.cpp:1526
CNcbiOstream & x_NewWrite(CNcbiOstream &os, TDiagWriteFlags fl=fNone) const
Definition: ncbidiag.cpp:5758
const CNcbiDiag & SetFile(const char *file) const
Set file name to post.
Definition: ncbidiag.cpp:7746
bool x_CanPrint(void)
Definition: ncbidiag.cpp:2444
void x_LogHitID(void) const
Definition: ncbidiag.cpp:2968
CNcbiDiag(EDiagSev sev=eDiag_Error, TDiagPostFlags post_flags=eDPF_Default)
Constructor.
Definition: ncbidiag.cpp:7709
void x_CreateUID(void) const
Definition: ncbidiag.cpp:1624
CStopWatch * m_ReopenTimer
Definition: ncbidiag.hpp:2782
CStreamDiagHandler_Base * m_Log
Definition: ncbidiag.hpp:2776
CDiagRestorer(void)
Captures current settings.
Definition: ncbidiag.cpp:7980
void ResetLogRates(void)
Definition: ncbidiag.cpp:1343
const string & GetHostIP(void) const
Get host IP address.
Definition: ncbidiag.hpp:2160
TCount m_ThrPost
Number of the post in the thread.
Definition: ncbidiag.hpp:1668
EDiagSevChange m_PostSeverityChange
Severity change.
Definition: ncbidiag.hpp:2974
int m_Severity
Message severity (if less that 0, then use current diagnostic severity level)
Definition: ncbidiag.hpp:3015
void SetHostIP(const string &ip)
Set host IP address.
Definition: ncbidiag.cpp:1844
~CFileDiagHandler(void)
Definition: ncbidiag.cpp:6742
int CompareDiagPostLevel(EDiagSev sev1, EDiagSev sev2)
Compare two severities.
Definition: ncbidiag.cpp:6157
static void x_LogEnvironment(void)
Definition: ncbidiag.cpp:3221
static const char * kProperty_ExitCode
Definition: ncbidiag.hpp:2057
void UnsetDiagPostFlag(EDiagPostFlag flag)
Unset the specified flag (globally).
Definition: ncbidiag.cpp:6075
unique_ptr< CStopWatch > m_StopWatch
Definition: ncbidiag.hpp:2368
string GetClient(void) const
Definition: ncbidiag.cpp:5977
CDiagHandler * GetDiagHandler(bool take_ownership, bool *current_ownership)
Get the currently set diagnostic handler class.
Definition: ncbidiag.cpp:6329
void SetDiagPostPrefix(const char *prefix)
Specify a string to prefix all subsequent error postings with.
Definition: ncbidiag.cpp:6097
void SetDoubleDiagHandler(void)
Output diagnostics using both old and new style handlers.
Definition: ncbidiag.cpp:8129
int TDiagWriteFlags
Definition: ncbidiag.hpp:1708
CDiagContext_Extra & PrintNcbiAppInfoOnRequest(void)
Definition: ncbidiag.cpp:2287
static string GetDefaultClientIP(void)
Get default client ip.
Definition: ncbidiag.cpp:2932
const string & GetAppName(void) const
Definition: ncbidiag.cpp:5991
CStreamDiagHandler(CNcbiOstream *os, bool quick_flush=true, const string &stream_name="")
Constructor.
Definition: ncbidiag.cpp:6422
bool m_OmitStackTrace
Definition: ncbidiag.hpp:1212
void RemoveFromDiag(void)
Remove this DiagHandler from diagnostics.
Definition: ncbidiag.cpp:7242
void SetAutoIncRequestIDOnPost(bool enable)
Auto-increment request ID with every posted message.
EDiagSev SetDiagDieLevel(EDiagSev die_sev)
Set the "die" (abort) level for the program.
Definition: ncbidiag.cpp:6196
void SetRequestStatus(int status)
EDiagFileType m_FileType
Definition: ncbidiag.hpp:2674
void Abort(void)
Smart abort function.
Definition: ncbidiag.cpp:8147
string x_GetModule(void) const
Definition: ncbidiag.cpp:5373
bool IsSetHitID(EHitIDSource src=eHitID_Any) const
Check if there's an explicit hit id or the default one.
const CNcbiDiag & SetFunction(const char *function) const
Set function name.
Definition: ncbidiag.cpp:7767
static void DiagValidate(const CDiagCompileInfo &info, const char *expression, const char *message)
Display validation message.
Definition: ncbidiag.cpp:7965
list< TExtraArg > TExtraArgs
Definition: ncbidiag.hpp:1675
size_t m_BufferLen
Length of m_Buffer.
Definition: ncbidiag.hpp:1653
static const char * kProperty_HostName
Definition: ncbidiag.hpp:2053
void SetDiagErrCodeInfo(CDiagErrCodeInfo *info, bool can_delete)
Set handler for processing error codes.
Definition: ncbidiag.cpp:7644
static void DiagAssertIfSuppressedSystemMessageBox(const CDiagCompileInfo &info, const char *expression, const char *message=NULL)
Same as DiagAssert but only if the system message box is suppressed.
Definition: ncbidiag.cpp:7955
static bool GetDefaultAutoIncRequestIDOnPost(void)
Get default auto-increment flag.
static TDiagPostFlags ForceImportantFlags(TDiagPostFlags flags)
Set important flags to their globally set values.
Definition: ncbidiag.cpp:7737
~CDiagContext(void)
Definition: ncbidiag.cpp:1337
static const char * SeverityName(EDiagSev sev)
Get a common symbolic name for the severity levels.
EDiagSev m_PrintSev
Definition: ncbidiag.hpp:1381
EDiagSev SetDiagPostLevel(EDiagSev post_sev)
Set the threshold severity for posting the messages.
Definition: ncbidiag.cpp:6129
EDiagTrace
Which setting disables/enables posting of "eDiag_Trace" messages.
Definition: ncbidiag.hpp:1547
EAction
Action to perform in guard's destructor.
Definition: ncbidiag.hpp:1303
ELogRate_Type
Type of logging rate limit.
Definition: ncbidiag.hpp:2276
void SetExitCode(int exit_code)
Set exit code.
Definition: ncbidiag.hpp:2176
CDiagFileHandleHolder * m_Handle
Definition: ncbidiag.hpp:2677
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
const string & GetEncodedHost(void) const
URL-encoded version of GetHost()
Definition: ncbidiag.cpp:1812
bool x_LogHitIDOnError(void) const
bool m_LoggedHitId
Definition: ncbidiag.hpp:2362
const char * m_File
Definition: ncbidiag.hpp:109
const CStopWatch & GetRequestTimer(void) const
Request execution timer.
void(* FDiagHandler)(const SDiagMessage &mess)
Diagnostic handler function type.
Definition: ncbidiag.hpp:2485
void SetExitSignal(int exit_sig)
Set exit signal.
Definition: ncbidiag.hpp:2185
SDiagMessage::EEventType m_EventType
Definition: ncbidiag.hpp:1918
const char * m_Class
Class name.
Definition: ncbidiag.hpp:1656
deque< SDiagMessage > TMessages
Save messages if the handle is unavailable.
Definition: ncbidiag.hpp:2682
unsigned int GetLogRate_Period(ELogRate_Type type) const
Logging rate control - the messages control period, seconds.
Definition: ncbidiag.cpp:1421
void WriteStdPrefix(CNcbiOstream &ostr, const SDiagMessage &msg) const
Write standard prefix to the stream.
Definition: ncbidiag.cpp:3163
bool GetReadOnly(void) const
Get current read-only flag.
EDiagSev GetSeverityCap(void) const
Get current severity cap for use in ePrintCapped mode.
Definition: ncbidiag.hpp:1355
string GetNextHitID(void) const
Create global unique request id.
Definition: ncbidiag.cpp:1715
string m_HostIP
Definition: ncbidiag.hpp:2356
TDiagPostFlags m_PostFlags
Post flags.
Definition: ncbidiag.hpp:2972
pair< string, string > TExtraArg
Definition: ncbidiag.hpp:1674
static NCBI_XNCBI_EXPORT void DiagAssert(const CDiagCompileInfo &info, const char *expression, const char *message=NULL)
Assert specified expression and report results.
Definition: ncbidiag.cpp:7944
static const char * kProperty_BytesRd
Definition: ncbidiag.hpp:2064
void InstallToDiag(void)
Install this DiagHandler into diagnostics.
Definition: ncbidiag.cpp:7225
string m_FunctName
Definition: ncbidiag.hpp:117
void SetProperty(const string &name, const string &value, EPropertyMode mode=eProp_Default)
Set application context property by name.
Definition: ncbidiag.cpp:1931
CFileHandleDiagHandler(const string &fname, EDiagFileType file_type=eDiagFile_All)
Constructor.
Definition: ncbidiag.cpp:6490
EDiagSev GetCollectSeverity(void) const
Get current collect severity.
Definition: ncbidiag.hpp:1349
SDiagMessage::TCount TCount
Definition: ncbidiag.hpp:2265
~CFileHandleDiagHandler(void)
Close file handle.
Definition: ncbidiag.cpp:6503
static bool IsUsingRootLog(void)
Check if the current diagnostics destination is /log/*.
Definition: ncbidiag.cpp:3868
void Flush(void)
Print the message and reset object.
Definition: ncbidiag.cpp:2332
bool IsSetDiagPostFlag(EDiagPostFlag flag, TDiagPostFlags flags=eDPF_Default)
Check if a specified flag is set.
SDiagMessage & operator=(const SDiagMessage &message)
Assignment of messages.
Definition: ncbidiag.cpp:4613
CDiagContext_Extra(const CDiagContext_Extra &args)
Copying the object will prevent printing it on destruction.
Definition: ncbidiag.cpp:2199
void SetLogRate_Period(ELogRate_Type type, unsigned int period)
Definition: ncbidiag.cpp:1434
void PrintProperties(void)
Forced dump of all set properties.
Definition: ncbidiag.cpp:2085
static bool IsUsingSystemThreadId(void)
Check if system TID is printed instead of CThread::GetSelf()
Definition: ncbidiag.cpp:3358
TInfo m_Info
Map storing error codes and descriptions.
Definition: ncbidiag.hpp:3086
CDiagAutoPrefix(const string &prefix)
Constructor.
Definition: ncbidiag.cpp:6009
void SetBytesRd(Int8 bytes)
CStreamDiagHandler_Base * x_GetHandler(EDiagFileType file_type) const
Definition: ncbidiag.cpp:7088
const char * GetFunction(void) const
Get function name of the current message.
const CNcbiDiag & Put(const volatile void *, const X &x) const
Generic method to post to diagnostic stream.
CSpinLock * m_HandleLock
Definition: ncbidiag.hpp:2678
CSharedHitId x_GetDefaultHitID(EDefaultHitIDFlags flag) const
Definition: ncbidiag.cpp:2997
static const string & GetHostLocation(void)
Get host location (be-md/st-va) from /etc/ncbi/location.
Definition: ncbidiag.cpp:3111
EDiagFileType
CDiagHandler –.
Definition: ncbidiag.hpp:2435
EDiagAppState
Application execution states shown in the std prefix.
Definition: ncbidiag.hpp:789
friend const CNcbiDiag & Endm(const CNcbiDiag &diag)
Flush current message, start new one.
string m_ClassName
Definition: ncbidiag.hpp:116
void(* FDiagCleanup)(void *data)
Diagnostic cleanup function type.
Definition: ncbidiag.hpp:2488
CDiagCompileInfo m_CompileInfo
Definition: ncbidiag.hpp:1214
list< string > m_PrefixList
List of prefixes.
Definition: ncbidiag.hpp:2971
static const string & GetHostRole(void)
Get host role (DEV/QA/TRY/PROD) from /etc/ncbi/role.
Definition: ncbidiag.cpp:3091
static void SetDefaultClientIP(const string &client_ip)
Set new default client ip.
Definition: ncbidiag.cpp:2938
CDiagContext_Extra & PrintNcbiAppInfoOnStart(void)
Definition: ncbidiag.cpp:2237
virtual void SetLogName(const string &log_name)
Definition: ncbidiag.cpp:6752
static void x_FinalizeSetupDiag(void)
Internal function, should be used only by CNcbiApplication.
Definition: ncbidiag.cpp:3501
bool SetLogFile(const string &file_name, EDiagFileType file_type, bool quick_flush)
Set new log file.
Definition: ncbidiag.cpp:6884
static void UpdateOnFork(TOnForkFlags flags)
Update diagnostics after fork().
Definition: logging.cpp:824
CDiagContext_Extra & SetType(const string &type)
Set extra message type.
Definition: ncbidiag.cpp:2754
bool ApproveMessage(SDiagMessage &msg, bool *show_warning)
Definition: ncbidiag.cpp:1476
CStreamDiagHandler_Base * m_Err
Definition: ncbidiag.hpp:2774
bool m_ApplogSeverityLocked
Limiting applog post level?
Definition: ncbidiag.hpp:2983
~CDiagAutoPrefix(void)
Remove the prefix automagically, when the object gets out of scope.
Definition: ncbidiag.cpp:6019
TDiagPostFlags SetDiagTraceAllFlags(TDiagPostFlags flags)
Versions of the above for extra trace flags.
Definition: ncbidiag.cpp:6081
const CNcbiDiag & x_Put(const CException &ex) const
Helper func for the exception-related Put()
Definition: ncbidiag.cpp:7817
string GetProperty(const string &name, EPropertyMode mode=eProp_Default) const
Get application context property by name, return empty string if the property is not set.
Definition: ncbidiag.cpp:2018
static void SetupDiag(EAppDiagStream ds=eDS_Default, CNcbiRegistry *config=NULL, EDiagCollectMessages collect=eDCM_NoChange, const char *cmd_logfile=NULL)
Application-wide diagnostics setup.
Definition: ncbidiag.cpp:3545
virtual void WriteMessage(const char *buf, size_t len, EDiagFileType file_type)
Write string to the log.
Definition: ncbidiag.cpp:6676
bool SetLogFile(const string &file_name, EDiagFileType file_type, bool quick_flush)
Set log files.
Definition: ncbidiag.cpp:7528
static const char * kProperty_SessionID
Definition: ncbidiag.hpp:2061
EDiagAppState GetAppState(void) const
Return application state for the current thread if it's set.
Definition: ncbidiag.cpp:2802
void InitMessages(size_t max_size=100)
Start collecting all messages (the collected messages can be flushed to a new destination later).
Definition: ncbidiag.cpp:3370
bool IsSetDiagHandler(void)
Check if diagnostic handler is set.
Definition: ncbidiag.cpp:6324
static void UseSystemThreadId(bool value=true)
Switch printing system TID (rather than CThread::GetSelf()) on/off.
Definition: ncbidiag.cpp:3364
static void SetUseRootLog(void)
@depracated The flag is always set now, the funcion still calls SetupDiag() for compatibility,...
Definition: ncbidiag.cpp:3493
string GetHitID(void) const
Get explicit hit id or the default one (from HTTP_NCBI_PHID etc).
bool Read(const string &file_name)
Read error description from specified file.
Definition: ncbidiag.cpp:8188
unique_ptr< CSharedHitId > m_DefaultHitId
Definition: ncbidiag.hpp:2361
static const char * kLogName_Syslog
Definition: syslog.hpp:110
virtual string GetLogName(void)
Get current diag posts destination.
Definition: ncbidiag.cpp:7255
const char * m_Function
Function name.
Definition: ncbidiag.hpp:1657
static bool IsMainThreadDataInitialized(void)
Definition: ncbidiag.cpp:912
#define ERR_POST(message)
Error posting with file, line number information but without error codes.
Definition: ncbidiag.hpp:186
CNcbiOstream & x_OldWrite(CNcbiOstream &os, TDiagWriteFlags fl=fNone) const
Definition: ncbidiag.cpp:5570
CDiagContext(void)
Definition: ncbidiag.cpp:1298
virtual string GetLogName(void)
Get current diag posts destination.
Definition: ncbidiag.cpp:6375
void SetDiagHandler(CDiagHandler *handler, bool can_delete)
Set the diagnostic handler using the specified diagnostic handler class.
Definition: ncbidiag.cpp:6288
TUID UpdateUID(TUID uid=0) const
Take the source UID and replace its timestamp part with the current time.
Definition: ncbidiag.cpp:1702
virtual void Reopen(TReopenFlags flags)
Reopen file to enable log rotation.
Definition: ncbidiag.cpp:7039
TPID m_PID
Process ID.
Definition: ncbidiag.hpp:1665
void SetDefaultHitID(const string &hit_id)
Set new global default hit id.
Definition: ncbidiag.cpp:3062
CDiagCollectGuard(void)
Set collectable severity and optionally applied print-severity cap to the current post level,...
Definition: ncbidiag.cpp:515
SDiagMessage::TExtraArgs TExtraArgs
Definition: ncbidiag.hpp:1864
const char * m_ErrText
Sometimes 'error' has no numeric code, but can be represented as text.
Definition: ncbidiag.hpp:1663
bool IsSetExplicitSessionID(void) const
Does not check default SID.
atomic< bool > m_TraceLogSuspended
Definition: ncbidiag.hpp:2382
~SDiagMessage(void)
Definition: ncbidiag.cpp:4574
static void sx_ThreadDataTlsCleanup(CDiagContextThreadData *value, void *cleanup_data)
Definition: ncbidiag.cpp:940
void SetDiagTrace(EDiagTrace how, EDiagTrace dflt)
Set the diagnostic trace settings.
Definition: ncbidiag.cpp:6226
EDiagAppState GetAppState(void) const
Definition: ncbidiag.cpp:6000
const string & GetAppName(void) const
Get application name.
Definition: ncbidiag.cpp:1857
const char * GetClass(void) const
Get class name of the current message.
CDiagHandler * m_Handler
Class handler.
Definition: ncbidiag.hpp:2979
void x_PrintMessage(SDiagMessage::EEventType event, const string &message)
Definition: ncbidiag.cpp:3274
EDiagSev
Severity level for the posted diagnostics.
Definition: ncbidiag.hpp:650
const char * g_DiagUnknownFunction(void)
Definition: ncbidiag.cpp:8341
static void SetOldPostFormat(bool value)
Set old/new format flag.
Definition: ncbidiag.cpp:3352
void SetDefaultSessionID(const string &session_id)
Set new default session id.
Definition: ncbidiag.cpp:2893
EEventType m_Event
If the severity is eDPF_AppLog, m_Event contains event type.
Definition: ncbidiag.hpp:1672
TDiagPostFlags SetDiagPostAllFlags(TDiagPostFlags flags)
Set global post flags to "flags".
Definition: ncbidiag.cpp:6065
void SetCustomThreadSuffix(const string &suffix)
Set custom suffix to use on all threads in the server's pool.
Definition: ncbidiag.cpp:7219
bool x_NeedModule(void) const
Definition: ncbidiag.cpp:697
void SetFunction(const string &func)
Definition: ncbidiag.cpp:742
Uint8 GetDiagRequestId(void)
Get iteration number/request ID.
Definition: ncbidiag.cpp:1195
const char * GetFile(void) const
Get file used for the current message.
bool m_IgnoreToDie
Ignore to die on die sev.
Definition: ncbidiag.hpp:2975
static void SetLogTruncate(bool value)
Set log file truncation flag.
Definition: ncbidiag.cpp:3475
SDiagMessage::TExtraArg TExtraArg
Definition: ncbidiag.hpp:1863
CNcbiOstream * GetDiagStream(void)
Get current diagnostic stream (if it was set by SetDiagStream) or NULL.
Definition: ncbidiag.cpp:8108
unique_ptr< TMessages > m_Messages
Definition: ncbidiag.hpp:2369
void PrintStop(void)
Print exit message.
Definition: ncbidiag.cpp:2139
static NCBI_XNCBI_EXPORT void DiagFatal(const CDiagCompileInfo &info, const char *message)
Display fatal error message.
Definition: ncbidiag.cpp:7929
void SetUsername(const string &username)
Set username.
Definition: ncbidiag.cpp:1760
bool IsSetDiagErrCodeInfo(void)
Indicates whether an error-code processing handler has been set.
Definition: ncbidiag.cpp:7654
CDiagErrCodeInfo * m_ErrCodeInfo
Error code information.
Definition: ncbidiag.hpp:2981
unique_ptr< CRequestRateControl > m_AppLogRC
Definition: ncbidiag.hpp:2377
const string & GetHitId(void) const
Get hit id value.
Definition: request_ctx.hpp:91
static const char * kProperty_HostIP
Definition: ncbidiag.hpp:2054
const char * m_CurrFunctName
Definition: ncbidiag.hpp:113
CFileDiagHandler(void)
Constructor.
Definition: ncbidiag.cpp:6727
EDiagFileType x_GetDiagFileType(const SDiagMessage &msg) const
Definition: ncbidiag.cpp:7067
#define DIAG_TRACE
Diagnostic trace setting.
Definition: ncbidiag.hpp:1540
static bool StrToSeverityLevel(const char *str_sev, EDiagSev &sev)
Get severity from string.
Definition: ncbidiag.cpp:7904
EPropertyMode
Property visibility flag.
Definition: ncbidiag.hpp:2014
EDiagSev GetPrintSeverity(void) const
Get current print severity.
Definition: ncbidiag.hpp:1343
string GetDefaultSessionID(void) const
Get default session id.
Definition: logging.cpp:868
virtual void Post(const SDiagMessage &mess)
Post message to the handler.
Definition: ncbidiag.cpp:6434
static const char * kProperty_AppState
Per-thread properties.
Definition: ncbidiag.hpp:2059
int GetExitCode(void) const
Get exit code.
Definition: ncbidiag.hpp:2174
void SetOwnership(CStreamDiagHandler_Base *handler, bool own)
Change ownership for the given handler if it's currently installed.
Definition: ncbidiag.cpp:6838
virtual bool AllowAsyncWrite(const SDiagMessage &msg) const
Check if the handler supports async writes.
Definition: ncbidiag.cpp:6661
void SetFile(const string &file)
Definition: ncbidiag.cpp:722
void SetClass(const string &cls)
Definition: ncbidiag.cpp:757
void SetDiagTraceFlag(EDiagPostFlag flag)
Definition: ncbidiag.cpp:6086
void x_ResetHandler(CStreamDiagHandler_Base **ptr, bool *owned)
Definition: ncbidiag.cpp:6760
CTime GetTime(void) const
Get time and date - current or parsed.
Definition: ncbidiag.cpp:5341
void x_LogHitID_WithLock(void) const
Definition: ncbidiag.cpp:2983
CDiagErrCodeInfo * GetDiagErrCodeInfo(bool take_ownership)
Get handler for processing error codes.
Definition: ncbidiag.cpp:7659
virtual void Post(const SDiagMessage &mess)
Post message to the handler.
Definition: ncbidiag.cpp:7100
virtual void Post(const SDiagMessage &mess)
Post message to the handler.
Definition: ncbidiag.cpp:6611
bool m_PrintStackTrace
Definition: ncbidiag.hpp:1687
virtual string GetLogName(void)
Get current diag posts destination.
Definition: ncbidiag.cpp:6408
friend class CDiagContext_Extra
Definition: ncbidiag.hpp:2320
static bool IsApplogSeverityLocked(void)
When using applog, the diag post level is locked to Warning.
Definition: ncbidiag.hpp:2296
unique_ptr< CEncodedString > m_DefaultSessionId
Definition: ncbidiag.hpp:2360
string GetLogFile(EDiagFileType file_type)
Get log file name for the given log type.
Definition: ncbidiag.cpp:7612
static const char * kProperty_BytesWr
Definition: ncbidiag.hpp:2065
~CNcbiLogFields(void)
Definition: ncbidiag.cpp:3916
void SetDiagStream(CNcbiOstream *os, bool quick_flush, FDiagCleanup cleanup, void *cleanup_data, const string &stream_name)
Set diagnostic stream.
Definition: ncbidiag.cpp:8083
unique_ptr< CEncodedString > m_AppName
Definition: ncbidiag.hpp:2358
void SetAbortHandler(FAbortHandler func)
Set/unset abort handler.
Definition: ncbidiag.cpp:8141
CNcbiLogFields(const string &source)
Load fields to be logged from NCBI_LOG_FIELDS environment variable.
Definition: ncbidiag.cpp:3897
CDiagCompileInfo(void)
CDiagCompileInfo::
Definition: logging.cpp:1284
virtual void Post(const SDiagMessage &mess)
Implementation of CDiagHandler.
Definition: ncbidiag.cpp:7267
EDiagFilter
Diag severity types to put the filter on.
Definition: ncbidiag.hpp:2528
EDiagSev GetSeverity(void) const
Get severity of the current message.
EAction GetAction(void) const
Get selected on-destroy action.
Definition: ncbidiag.hpp:1360
static void ParseDiagStream(CNcbiIstream &in, INextDiagMessage &func)
Stream parser.
Definition: ncbidiag.cpp:5233
void x_SetHandler(CStreamDiagHandler_Base **member, bool *own_member, CStreamDiagHandler_Base *handler, bool own)
Definition: ncbidiag.cpp:6798
unsigned int GetLogRate_Limit(ELogRate_Type type) const
Logging rate control - max number of messages per period.
Definition: ncbidiag.cpp:1367
bool m_TypedExtra
Set to true if this is a typed extra message (the arguments include "NCBIEXTRATYPE=<extra-type>").
Definition: ncbidiag.hpp:1681
virtual void WriteMessage(const char *buf, size_t len, EDiagFileType file_type)
Write string to the log.
Definition: ncbidiag.cpp:7143
static TCount GetProcessPostNumber(EPostNumberIncrement inc)
Return process post number (incrementing depends on the flag).
Definition: ncbidiag.cpp:3848
static const char * kProperty_ReqStatus
Definition: ncbidiag.hpp:2062
string GetEncodedSessionID(void) const
Get URL-encoded session ID.
void g_Diag_Use_RWLock(bool enable)
Use RW-lock for synchronization rather than mutex.
Definition: ncbidiag.cpp:88
void SetGlobalAppState(EDiagAppState state)
Set global application state.
Definition: ncbidiag.cpp:2809
SDiagMessage::TUID TUID
Definition: ncbidiag.hpp:1975
bool m_CanDeleteHandler
Can handler be deleted?
Definition: ncbidiag.hpp:2980
EDiagAppState GetAppState(void) const
Application state.
const CNcbiDiag & SetModule(const char *module) const
Set module name.
Definition: ncbidiag.cpp:7753
unique_ptr< CRequestRateControl > m_ErrLogRC
Definition: ncbidiag.hpp:2378
virtual bool AllowAsyncWrite(const SDiagMessage &msg) const
Check if the handler supports async writes.
Definition: ncbidiag.cpp:7124
virtual bool AllowAsyncWrite(const SDiagMessage &msg) const
Check if the handler supports async writes.
Definition: ncbidiag.cpp:6383
SDiagMessageData * m_Data
Definition: ncbidiag.hpp:1752
virtual CNcbiOstream * GetStream(void)
Definition: ncbidiag.hpp:2579
const string & GetUsername(void) const
Get username.
Definition: ncbidiag.cpp:1754
bool IgnoreDiagDieLevel(bool ignore)
Ignore the die level settings.
Definition: ncbidiag.cpp:6217
string GetSession(void) const
Definition: ncbidiag.cpp:5984
@ fResetOnStart
Reset values when printing request-start.
@ fTruncate
Truncate file to zero size.
Definition: ncbidiag.hpp:2471
@ fDefault
Default reopen flags:
Definition: ncbidiag.hpp:2473
@ fCheck
Reopen only if necessary.
Definition: ncbidiag.hpp:2472
@ eDPF_TID
Thread ID.
Definition: ncbidiag.hpp:705
@ eDPF_AtomicWrite
This flag is deprecated and ignored - all log writes are atomic.
Definition: ncbidiag.hpp:763
@ eDPF_ErrCodeUseSeverity
Use severity from error code (default)
Definition: ncbidiag.hpp:703
@ eDPF_Location
Include class and function if any.
Definition: ncbidiag.hpp:704
@ eDPF_OmitSeparator
No '—' separator before message.
Definition: ncbidiag.hpp:754
@ eDPF_MergeLines
Escape EOLs.
Definition: ncbidiag.hpp:751
@ eDPF_ErrCodeMsgInFront
Put ErrCode text in front of the message.
Definition: ncbidiag.hpp:750
@ eDPF_ErrCodeExplanation
Error explanation (default)
Definition: ncbidiag.hpp:702
@ eDPF_IsNote
Print "Note[X]" severity name.
Definition: ncbidiag.hpp:757
@ eDPF_DateTime
Include date and time.
Definition: ncbidiag.hpp:700
@ eDPF_ErrorID
Error code and subcode (default)
Definition: ncbidiag.hpp:698
@ eDPF_Severity
Severity (default)
Definition: ncbidiag.hpp:697
@ eDPF_OmitInfoSev
No sev. indication if eDiag_Info.
Definition: ncbidiag.hpp:753
@ eDPF_Default
Use global default flags (merge with).
Definition: ncbidiag.hpp:771
@ eDPF_IsConsole
Send the message to 'console' regardless of it's severity.
Definition: ncbidiag.hpp:767
@ eDPF_Line
Source line.
Definition: ncbidiag.hpp:695
@ eDPF_Trace
Default flags to use when tracing.
Definition: ncbidiag.hpp:722
@ eDPF_File
File name (not full path)
Definition: ncbidiag.hpp:693
@ eDPF_UseExactUserFlags
Use flags provided by user as-is, do not allow CNcbiDiag to replace "important" flags by the globally...
Definition: ncbidiag.hpp:782
@ eDPF_ImportantFlagsMask
Important bits which should be taken from the globally set flags even if a user attempts to override ...
Definition: ncbidiag.hpp:776
@ eDPF_ErrCodeMessage
Error code message (default)
Definition: ncbidiag.hpp:701
@ eDPF_LongFilename
Full file path.
Definition: ncbidiag.hpp:694
@ eDPF_AppLog
Post message to application log.
Definition: ncbidiag.hpp:756
@ eDPF_Prefix
Prefix (default)
Definition: ncbidiag.hpp:696
@ eDiagSC_Enable
Enable change severity level.
Definition: ncbidiag.hpp:669
@ eDiagSC_Disable
Disable change severity level.
Definition: ncbidiag.hpp:668
@ eDiagSC_Unknown
Status of changing severity is unknown (first call)
Definition: ncbidiag.hpp:667
@ eDCM_Discard
Discard the collected messages without flushing.
Definition: ncbidiag.hpp:1805
@ eDCM_Init
Start collecting messages (with limit), do nothing if already initialized.
Definition: ncbidiag.hpp:1799
@ eDCM_NoChange
Continue collecting messages if already started.
Definition: ncbidiag.hpp:1803
@ eDCM_InitNoLimit
Start collecting messages without limit (must stop collecting later using eDCM_Flush or eDCM_Discard)...
Definition: ncbidiag.hpp:1801
@ eDCM_Flush
Flush the collected messages and stop collecting.
Definition: ncbidiag.hpp:1804
@ fNoEndl
No end of line.
Definition: ncbidiag.hpp:1704
@ fNoPrefix
No std prefix.
Definition: ncbidiag.hpp:1705
@ eDS_Default
Try standard log file (app.name + ".log") in /log/, use stderr on failure.
Definition: ncbidiag.hpp:1790
@ eDS_ToMemory
Keep in a temp.memory buffer, see FlushMessages()
Definition: ncbidiag.hpp:1785
@ eDS_User
Leave as was previously set (or not set) by user.
Definition: ncbidiag.hpp:1787
@ eDS_Disable
Don't write it anywhere.
Definition: ncbidiag.hpp:1786
@ eDS_AppSpecific
Call the application's SetupDiag_AppSpecific()
Definition: ncbidiag.hpp:1788
@ eDS_ToStdlog
Try standard log file (app.name + ".log") in /log/ and current directory, use stderr if both fail.
Definition: ncbidiag.hpp:1783
@ eDS_ToStdout
To standard output stream.
Definition: ncbidiag.hpp:1781
@ eDS_ToStderr
To standard error stream.
Definition: ncbidiag.hpp:1782
@ eDS_ToSyslog
To system log daemon.
Definition: ncbidiag.hpp:1792
@ ePostNumber_NoIncrement
Get post number without incrementing it.
Definition: ncbidiag.hpp:1812
@ ePostNumber_Increment
Increment and return the new post number.
Definition: ncbidiag.hpp:1813
@ eEvent_RequestStop
Finish processing request.
Definition: ncbidiag.hpp:1645
@ eEvent_PerfLog
Performance log.
Definition: ncbidiag.hpp:1646
@ eEvent_RequestStart
Start processing request.
Definition: ncbidiag.hpp:1644
@ eEvent_Start
Application start.
Definition: ncbidiag.hpp:1641
@ eEvent_Extra
Other application events.
Definition: ncbidiag.hpp:1643
@ eEvent_Stop
Application exit.
Definition: ncbidiag.hpp:1642
@ eDT_Enable
Enable messages of severity "eDiag_Trace".
Definition: ncbidiag.hpp:1550
@ eDT_Disable
Ignore messages of severity "eDiag_Trace".
Definition: ncbidiag.hpp:1549
@ eDT_Default
Restores the default tracing context.
Definition: ncbidiag.hpp:1548
@ ePrintCapped
Print collected messages at reduced severity.
Definition: ncbidiag.hpp:1306
@ ePrint
Print all collected messages as is.
Definition: ncbidiag.hpp:1304
@ eDiscard
Discard collected messages, default.
Definition: ncbidiag.hpp:1305
@ eLogRate_Err
Error log.
Definition: ncbidiag.hpp:2278
@ eLogRate_Trace
Trace log.
Definition: ncbidiag.hpp:2279
@ eLogRate_App
Application log.
Definition: ncbidiag.hpp:2277
@ fOnFork_ResetTimer
Reset execution timer.
Definition: ncbidiag.hpp:1946
@ fOnFork_AsyncSafe
After a fork() in a multithreaded program, the child can safely call only async-signal-safe functions...
Definition: ncbidiag.hpp:1947
@ fOnFork_PrintStart
Log app-start.
Definition: ncbidiag.hpp:1945
@ eHitID_Request
Check if per-request hit id is set.
@ eHidID_Existing
Check if any hit is already available (will not be generated on request).
@ eDiagFile_Trace
Trace log file.
Definition: ncbidiag.hpp:2438
@ eDiagFile_Perf
Perf log file.
Definition: ncbidiag.hpp:2439
@ eDiagFile_Err
Error log file.
Definition: ncbidiag.hpp:2436
@ eDiagFile_All
All log files.
Definition: ncbidiag.hpp:2440
@ eDiagFile_Log
Access log file.
Definition: ncbidiag.hpp:2437
@ eDiagAppState_RequestEnd
RE.
Definition: ncbidiag.hpp:796
@ eDiagAppState_AppEnd
AE.
Definition: ncbidiag.hpp:793
@ eDiagAppState_AppBegin
AB.
Definition: ncbidiag.hpp:791
@ eDiagAppState_AppRun
A.
Definition: ncbidiag.hpp:792
@ eDiagAppState_RequestBegin
RB.
Definition: ncbidiag.hpp:794
@ eDiagAppState_NotSet
Reserved value, never used in messages.
Definition: ncbidiag.hpp:790
@ eDiagAppState_Request
R.
Definition: ncbidiag.hpp:795
@ eDiag_Trace
Trace message.
Definition: ncbidiag.hpp:657
@ eDiag_Info
Informational message.
Definition: ncbidiag.hpp:651
@ eDiag_Error
Error message.
Definition: ncbidiag.hpp:653
@ eDiag_Warning
Warning message.
Definition: ncbidiag.hpp:652
@ eDiag_Fatal
Fatal error – guarantees exit(or abort)
Definition: ncbidiag.hpp:655
@ eDiagSevMin
Verbosity level for min. severity.
Definition: ncbidiag.hpp:660
@ eDiag_Critical
Critical error message.
Definition: ncbidiag.hpp:654
@ eDiagSevMax
Verbosity level for max. severity.
Definition: ncbidiag.hpp:661
@ eProp_Default
Auto-mode for known properties, local for others.
Definition: ncbidiag.hpp:2015
@ eProp_Thread
The property has separate value in each thread.
Definition: ncbidiag.hpp:2017
@ eProp_Global
The property is global for the application.
Definition: ncbidiag.hpp:2016
@ eDiagFilter_All
for all non-FATAL
Definition: ncbidiag.hpp:2531
@ eDiagFilter_Post
for all non-TRACE, non-FATAL
Definition: ncbidiag.hpp:2530
@ eDiagFilter_Trace
for TRACEs only
Definition: ncbidiag.hpp:2529
const string & GetModule(void) const
Get module name used for reporting.
Definition: ncbiexpt.hpp:1017
bool IsSetFlag(EFlags flag) const
Check if the flag is set.
Definition: ncbiexpt.hpp:1050
virtual void ReportExtra(ostream &out) const
Report "non-standard" attributes.
Definition: ncbiexpt.cpp:428
virtual const char * GetType(void) const
Get class name as a string.
Definition: ncbiexpt.cpp:268
void Critical(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1203
void Error(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1197
const string & GetFile(void) const
Get file name used for reporting.
Definition: ncbiexpt.hpp:1011
TErrCode GetErrCode(void) const
Get error code.
Definition: ncbiexpt.cpp:453
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
const string & GetMsg(void) const
Get message string.
Definition: ncbiexpt.cpp:461
void Warning(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1191
bool HasMainText(void) const
Check if exception has main text in the chain.
Definition: ncbiexpt.hpp:1044
const string & GetClass(void) const
Get class name used for reporting.
Definition: ncbiexpt.hpp:1023
#define NCBI_THROW2(exception_class, err_code, message, extra)
Throw exception with extra parameter.
Definition: ncbiexpt.hpp:1754
const string & GetFunction(void) const
Get function name used for reporting.
Definition: ncbiexpt.hpp:1029
EDiagSev GetSeverity(void) const
Get exception severity.
Definition: ncbiexpt.hpp:999
virtual const char * GetErrCodeString(void) const
Get error code interpreted as text.
Definition: ncbiexpt.cpp:444
int GetLine(void) const
Get line number where error occurred.
Definition: ncbiexpt.hpp:1032
const CException * GetPredecessor(void) const
Get "previous" exception from the backlog.
Definition: ncbiexpt.hpp:1041
void Info(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1185
const CStackTrace * GetStackTrace(void) const
Get the saved stack trace if available or NULL.
Definition: ncbiexpt.cpp:434
@ eCore
Generic corelib error.
Definition: ncbiexpt.hpp:1482
@ fConsole
Mark the exception with this flag if the exception is supposed to be extra-visible,...
Definition: ncbiexpt.hpp:900
static string NormalizePath(const string &path, EFollowLinks follow_links=eIgnoreLinks)
Normalize a path.
Definition: ncbifile.cpp:820
static string CreateAbsolutePath(const string &path, ERelativeToWhat rtw=eRelativeToCwd)
Get an absolute path from some, possibly relative, path.
Definition: ncbifile.cpp:665
string GetDir(EIfEmptyPath mode=eIfEmptyPath_Current) const
Get the directory component for this directory entry.
Definition: ncbifile.cpp:475
static bool IsAbsolutePath(const string &path)
Check if a "path" is absolute for the current OS.
Definition: ncbifile.cpp:508
string GetBase(void) const
Get the base entry name without extension.
Definition: ncbifile.hpp:3924
static mode_t MakeModeT(TMode user_mode, TMode group_mode, TMode other_mode, TSpecialModeBits special)
Construct mode_t value from permission modes.
Definition: ncbifile.cpp:1193
static Uint8 GetFreeDiskSpace(const string &path)
Get free disk space information.
Definition: ncbifile.cpp:5328
static string ConvertToOSPath(const string &path)
Convert "path" on any OS to the current OS-dependent path.
Definition: ncbifile.cpp:745
static char GetPathSeparator(void)
Get path separator symbol specific for the current platform.
Definition: ncbifile.cpp:433
static string ConcatPath(const string &first, const string &second)
Concatenate two parts of the path for the current OS.
Definition: ncbifile.cpp:776
unsigned int mode_t
Definition: ncbifile.hpp:84
string GetExt(void) const
Get extension name.
Definition: ncbifile.hpp:3932
virtual bool Exists(void) const
Check existence of file.
Definition: ncbifile.hpp:4038
@ fRF_Overwrite
Remove destination if it exists.
Definition: ncbifile.hpp:611
@ fRead
Read permission.
Definition: ncbifile.hpp:1153
@ fWrite
Write permission.
Definition: ncbifile.hpp:1152
@ eUnknown
Definition: app_popup.hpp:72
EStringType
String type.
Definition: serialdef.hpp:185
TObjectType * GetPointer(void) THROWS_NONE
Get pointer,.
Definition: ncbiobj.hpp:998
void AddReference(void) const
Add reference to object.
Definition: ncbiobj.hpp:489
void RemoveReference(void) const
Remove reference to object.
Definition: ncbiobj.hpp:500
static void EnableConfigDump(bool enable)
Definition: ncbi_param.cpp:56
@ eParam_NoThread
Do not use per-thread values.
Definition: ncbi_param.hpp:418
#define NCBI_DEPRECATED
uint32_t Uint4
4-byte (32-bit) unsigned integer
Definition: ncbitype.h:103
uint16_t Uint2
2-byte (16-bit) unsigned integer
Definition: ncbitype.h:101
int64_t Int8
8-byte (64-bit) signed integer
Definition: ncbitype.h:104
uint64_t Uint8
8-byte (64-bit) unsigned integer
Definition: ncbitype.h:105
#define kMax_UInt
Definition: ncbi_limits.h:185
static TPid GetPid(void)
Get process identifier (pid) for the current process.
virtual const string & Get(const string &section, const string &name, TFlags flags=0) const
Get the parameter value.
Definition: ncbireg.cpp:262
virtual void EnumerateEntries(const string &section, list< string > *entries, TFlags flags=fAllLayers) const
Enumerate parameter names for a specified section.
Definition: ncbireg.cpp:514
virtual string GetString(const string &section, const string &name, const string &default_value, TFlags flags=0) const
Get the parameter string value.
Definition: ncbireg.cpp:321
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
#define NcbiEndl
Definition: ncbistre.hpp:548
CNcbiIstream & NcbiGetlineEOL(CNcbiIstream &is, string &str, string::size_type *count=NULL)
Read from "is" to "str" the next line (taking into account platform specifics of End-of-Line)
bool IsOssEmpty(CNcbiOstrstream &oss)
Definition: ncbistre.hpp:831
IO_PREFIX::ostream CNcbiOstream
Portable alias for ostream.
Definition: ncbistre.hpp:149
#define NcbiFlush
Definition: ncbistre.hpp:550
CNcbistrstream_Base< IO_PREFIX::ostrstream, IOS_BASE::out > CNcbiOstrstream
Definition: ncbistre.hpp:286
IO_PREFIX::istream CNcbiIstream
Portable alias for istream.
Definition: ncbistre.hpp:146
#define NcbiCerr
Definition: ncbistre.hpp:544
IO_PREFIX::ifstream CNcbiIfstream
Portable alias for ifstream.
Definition: ncbistre.hpp:439
static bool StringToBool(const CTempString str)
Convert string to bool.
Definition: ncbistr.cpp:2821
NCBI_NS_STD::string::size_type SIZE_TYPE
Definition: ncbistr.hpp:132
static string Int8ToString(Int8 value, TNumToStringFlags flags=0, int base=10)
Convert Int8 to string.
Definition: ncbistr.hpp:5159
void Parse(const CTempString str, NStr::EMergeDelims merge_argsep=NStr::eMergeDelims)
Parse the string.
Definition: ncbistr.hpp:4698
static string DoubleToString(double value, int precision=-1, TNumToStringFlags flags=0)
Convert double to string.
Definition: ncbistr.hpp:5187
string Merge(void) const
Merge name-value pairs into a single string using the currently set separators and the provided encod...
Definition: ncbistr.hpp:4753
static int StringToNonNegativeInt(const CTempString str, TStringToNumFlags flags=0)
Convert string to non-negative integer value.
Definition: ncbistr.cpp:457
#define kEmptyStr
Definition: ncbistr.hpp:123
static int CompareNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive compare of a substring with another string.
Definition: ncbistr.cpp:219
static int StringToInt(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to int.
Definition: ncbistr.cpp:630
static Int8 StringToInt8(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to Int8.
Definition: ncbistr.cpp:793
static list< string > & Split(const CTempString str, const CTempString delim, list< string > &arr, TSplitFlags flags=0, vector< SIZE_TYPE > *token_pos=NULL)
Split a string using specified delimiters.
Definition: ncbistr.cpp:3461
static bool MatchesMask(CTempString str, CTempString mask, ECase use_case=eCase)
Match "str" against the "mask".
Definition: ncbistr.cpp:389
static string LongToString(long value, TNumToStringFlags flags=0, int base=10)
Convert Int to string.
Definition: ncbistr.hpp:5141
char TXChar
Definition: ncbistr.hpp:172
const char * g_GetNcbiString(ENcbiStrings what)
Definition: ncbi_strings.c:42
#define NPOS
Definition: ncbistr.hpp:133
CTempString & assign(const char *src_str, size_type len)
Assign new values to the content of the a string.
Definition: tempstr.hpp:733
static const string BoolToString(bool value)
Convert bool to string.
Definition: ncbistr.cpp:2815
static string JoinNumeric(TInputIterator from, TInputIterator to, const CTempString &delim)
Definition: ncbistr.hpp:2715
static string IntToString(int value, TNumToStringFlags flags=0, int base=10)
Convert int to string.
Definition: ncbistr.hpp:5084
#define _T_STDSTRING(x)
Definition: ncbistr.hpp:180
static int HexChar(char ch)
Convert character to integer.
Definition: ncbistr.hpp:5196
const char * data(void) const
Return a pointer to the array represented.
Definition: tempstr.hpp:313
EStringType
Type of string to be decoded.
Definition: ncbistr.hpp:4553
#define _T_CSTRING(x)
Definition: ncbistr.hpp:182
#define _T_XCSTRING(x)
Definition: ncbistr.hpp:181
IStringDecoder * GetDecoder(void)
Get decoder or NULL. Does not affect decoder ownership.
Definition: ncbistr.hpp:4676
EStringType
Type of string to be decoded.
Definition: ncbistr.hpp:4537
virtual string Decode(const CTempString src, EStringType stype) const =0
Decode the string.
static string UIntToString(unsigned int value, TNumToStringFlags flags=0, int base=10)
Convert UInt to string.
Definition: ncbistr.hpp:5109
static bool StartsWith(const CTempString str, const CTempString start, ECase use_case=eCase)
Check if a string starts with a specified prefix value.
Definition: ncbistr.hpp:5412
const TStrPairs & GetPairs(void) const
Read data.
Definition: ncbistr.hpp:4797
#define _TX(x)
Definition: ncbistr.hpp:176
static Uint8 StringToUInt8(const CTempString str, TStringToNumFlags flags=0, int base=10)
Convert string to Uint8.
Definition: ncbistr.cpp:873
static bool SplitInTwo(const CTempString str, const CTempString delim, string &str1, string &str2, TSplitFlags flags=0)
Split a string into two pieces using the specified delimiters.
Definition: ncbistr.cpp:3554
size_type length(void) const
Return the length of the represented array.
Definition: tempstr.hpp:320
static string ULongToString(unsigned long value, TNumToStringFlags flags=0, int base=10)
Convert unsigned long to string.
Definition: ncbistr.hpp:5150
static bool IsIPAddress(const CTempStringEx str)
Check if the string contains a valid IP address.
Definition: ncbistr.cpp:6396
static bool EqualNocase(const CTempString s1, SIZE_TYPE pos, SIZE_TYPE n, const char *s2)
Case-insensitive equality of a substring with another string.
Definition: ncbistr.hpp:5353
static enable_if< is_arithmetic< TNumeric >::value||is_convertible< TNumeric, Int8 >::value, string >::type NumericToString(TNumeric value, TNumToStringFlags flags=0, int base=10)
Convert numeric value to string.
Definition: ncbistr.hpp:673
static string & ReplaceInPlace(string &src, const string &search, const string &replace, SIZE_TYPE start_pos=0, SIZE_TYPE max_replace=0, SIZE_TYPE *num_replace=0)
Replace occurrences of a substring within a string.
Definition: ncbistr.cpp:3405
static string & ToUpper(string &str)
Convert string to upper case – string& version.
Definition: ncbistr.cpp:424
static string TruncateSpaces(const string &str, ETrunc where=eTrunc_Both)
Truncate spaces in a string.
Definition: ncbistr.cpp:3186
const char *const kEmptyCStr
Empty "C" string (points to a '\0').
Definition: ncbistr.cpp:68
size_type size(void) const
Return the length of the represented array.
Definition: tempstr.hpp:327
static string & ToLower(string &str)
Convert string to lower case – string& version.
Definition: ncbistr.cpp:405
static string UInt8ToString(Uint8 value, TNumToStringFlags flags=0, int base=10)
Convert UInt8 to string.
Definition: ncbistr.hpp:5168
@ eNcbiStrings_PHID
Definition: ncbi_strings.h:56
@ fConvErr_NoThrow
Do not throw an exception on error.
Definition: ncbistr.hpp:285
@ fSplit_Truncate
Definition: ncbistr.hpp:2501
@ fSplit_Tokenize
All delimiters are merged and trimmed, to get non-empty tokens only.
Definition: ncbistr.hpp:2508
@ fSplit_MergeDelimiters
Merge adjacent delimiters.
Definition: ncbistr.hpp:2498
@ fDoubleFixed
DoubleToString*(): Use n.nnnn format for double conversions.
Definition: ncbistr.hpp:255
@ eNocase
Case insensitive compare.
Definition: ncbistr.hpp:1206
TValue * GetValue(void)
Definition: ncbithr.hpp:335
#define NCBI_HAVE_CONDITIONAL_VARIABLE
CConditionVariable –.
Definition: ncbimtx.hpp:1437
bool Run(TRunMode flags=fRunDefault)
Run the thread.
Definition: ncbithr.cpp:724
static TID GetSelf(void)
Definition: ncbithr.cpp:515
void Wait(void)
Wait on semaphore.
Definition: ncbimtx.cpp:1787
static void SetCurrentThreadName(const CTempString &)
Set name for the current thread.
Definition: ncbithr.cpp:958
static bool IsMain(void)
Definition: ncbithr.cpp:537
void SetValue(TValue *value, FCleanup cleanup=0, void *cleanup_data=0, CTlsBase::ENativeThreadCleanup native=CTlsBase::eSkipCleanup)
Definition: ncbithr.hpp:338
void Post(unsigned int count=1)
Increment the semaphore by "count".
Definition: ncbimtx.cpp:1971
void Join(void **exit_data=0)
Wait for the thread termination.
Definition: ncbithr.cpp:863
static TThreadSystemID GetCurrentThreadSystemID(void)
Get the current thread ID.
Definition: ncbimtx.hpp:152
@ eDoCleanup
Definition: ncbithr.hpp:79
bool IsRunning(void) const
Check state of stopwatch.
Definition: ncbitime.hpp:2835
double Restart(void)
Return time elapsed since first Start() or last Restart() call (in seconds).
Definition: ncbitime.hpp:2816
double Elapsed(void) const
Return time elapsed since first Start() or last Restart() call (in seconds).
Definition: ncbitime.hpp:2775
CTime Truncate(const CTime &t)
Definition: ncbitime.hpp:2194
string AsString(const CTimeFormat &format=kEmptyStr, TSeconds out_tz=eCurrentTimeZone) const
Transform time to string.
Definition: ncbitime.cpp:1512
bool IsEmpty(void) const
Is time object empty (date and time)?
Definition: ncbitime.hpp:2377
string AsString(const CTimeFormat &fmt=kEmptyStr) const
Transform stopwatch time to string.
Definition: ncbitime.cpp:4149
CTime GetFastLocalTime(void)
Quick and dirty getter of local time.
Definition: ncbitime.cpp:4167
CTime GetLocalTime(void)
Get local time.
Definition: ncbitime.cpp:3988
@ eCurrent
Use current time. See also CCurrentTime.
Definition: ncbitime.hpp:300
@ eGmt
GMT (Greenwich Mean Time)
Definition: ncbitime.hpp:308
static const unsigned int kNoLimit
Special value for maximum number of allowed requests per period.
@ eErrCode
Return immediately with err code == FALSE.
@ eDiscrete
Uses fixed time frame to check number of requests.
string GetExtraValue(EExtra key, const string &default_value=kEmptyStr) const
Definition: version.cpp:464
int GetMajor(void) const
Major version.
const SBuildInfo & GetBuildInfo() const
Get build info (date and tag, if set)
Definition: version.cpp:695
const CVersionInfo & GetVersionInfo() const
Get version information.
Definition: version.cpp:676
static CVersionInfo GetPackageVersion(void)
Definition: version.cpp:705
int GetMinor(void) const
Minor version.
string date
Definition: version_api.hpp:79
static string GetPackageName(void)
Definition: version.cpp:700
int GetPatchLevel(void) const
Patch level.
#define NCBI_SBUILDINFO_DEFAULT()
Definition: version.hpp:119
static string ExtraNameAppLog(EExtra key)
Definition: version.cpp:501
@ eTeamCityBuildNumber
Definition: version_api.hpp:69
@ eRevision
Not necessarily numeric.
Definition: version_api.hpp:76
@ eTeamCityProjectName
Definition: version_api.hpp:67
@ eSubversionRevision
Numeric if present.
Definition: version_api.hpp:71
@ eStableComponentsVersion
Definition: version_api.hpp:72
@ eTeamCityBuildConf
Definition: version_api.hpp:68
@ eDevelopmentVersion
Definition: version_api.hpp:73
@ eProductionVersion
Definition: version_api.hpp:74
#define ErrCode()
Get the error code for the last failed system function.
Definition: mdb.c:377
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
#define NCBI_DEVELOPMENT_VER
Definition of all error codes used in corelib (xncbi.lib).
#define DEBUG
Definition: config.h:32
where boath are integers</td > n< td ></td > n</tr > n< tr > n< td > tse</td > n< td > optional</td > n< td > String</td > n< td class=\"description\"> TSE option controls what blob is orig
FILE * file
char * buf
int i
if(yy_accept[yy_current_state])
yy_size_t n
int len
CBioseq_Base_Info & GetBase(CTSE_Info &tse, const CBioObjectId &id)
static void text(MDB_val *v)
Definition: mdb_dump.c:62
static MDB_envinfo info
Definition: mdb_load.c:37
mdb_mode_t mode
Definition: lmdb++.h:38
const struct ncbi::grid::netcache::search::fields::KEY key
const GenericPointer< typename T::ValueType > T2 value
Definition: pointer.h:1227
const CharType(& source)[N]
Definition: pointer.h:1149
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
#define NCBI_TEAMCITY_BUILDCONF_NAME
#define NCBI_TEAMCITY_BUILD_ID
#define NCBI_SUBVERSION_REVISION
#define NCBI_TEAMCITY_BUILD_NUMBER
#define NCBI_TEAMCITY_PROJECT_NAME
#define HTTP_NCBI_SID
Definition: ncbi_comm.h:43
#define HTTP_NCBI_PHID
Definition: ncbi_comm.h:44
EIPRangeType t
Definition: ncbi_localip.c:101
Defines process management classes.
Common macro to detect used sanitizers and suppress memory leaks if run under LeakSanitizer.
#define NCBI_LSAN_DISABLE_GUARD
String constants used in NCBI C/C++ toolkit.
@ fSuppress_All
bool IsSuppressedDebugSystemMessageBox()
Check if system message box has been suppressed for debug library.
void SuppressSystemMessageBox(TSuppressSystemMessageBox mode=fSuppress_Default)
Suppress popup messages on execution errors.
static const char * kLogName_Stream
Definition: ncbidiag.cpp:179
bool x_IsEncodableChar(char c)
Definition: ncbidiag.cpp:4782
CDiagContext::TUID s_CreateUID(CDiagContext::TUID base)
Definition: ncbidiag.cpp:1593
static CSafeStatic< NCBI_PARAM_TYPE(Log, Session_Id)> s_DefaultSessionId
Definition: ncbidiag.cpp:2864
static const int kDiagW_Host
Definition: ncbidiag.cpp:3153
const int kLogReopenDelay
Definition: ncbidiag.cpp:6520
static CSafeStatic< SNcbiApplogKeywordsInit::TKeywords, SNcbiApplogKeywordsInit > s_NcbiApplogKeywords
Definition: ncbidiag.cpp:2619
static const char * kUnknown_App
Definition: ncbidiag.cpp:3160
static const int kDiagW_RID
Definition: ncbidiag.cpp:3149
static CSafeStatic< CDiagFilter > s_TraceFilter
Definition: ncbidiag.cpp:608
NCBI_PARAM_DEF_EX(bool, Diag, Old_Post_Format, true, eParam_NoThread, DIAG_OLD_POST_FORMAT)
const char * find_match(char lsep, char rsep, const char *start, const char *stop)
Definition: ncbidiag.cpp:766
Uint8 s_GetThreadId(void)
Definition: ncbidiag.cpp:887
bool OpenLogFileFromConfig(const string &logname)
Definition: ncbidiag.cpp:3481
static TDiagPostFlags s_PostFlags
Definition: ncbidiag.cpp:3949
void * s_DiagHandlerInitializer
Definition: ncbidiag.cpp:4022
static bool s_CreateHandler(const string &fname, unique_ptr< CStreamDiagHandler_Base > &handler, EDiagFileType file_type)
Definition: ncbidiag.cpp:6862
NCBI_PARAM_ENUM_DEF_EX(EDiagSev, Diag, Tee_Min_Severity, kTeeMinSeverityDef, eParam_NoThread, DIAG_TEE_MIN_SEVERITY)
static CSafeStatic< CDiagRecycler > s_DiagRecycler
Definition: ncbidiag.cpp:873
static CSafeStatic< NCBI_PARAM_TYPE(Diag, AppLog_Rate_Period)> s_AppLogRatePeriod
Definition: ncbidiag.cpp:347
bool s_IsSpecialLogName(const string &name)
Definition: ncbidiag.cpp:6717
static CSafeStatic< NCBI_PARAM_TYPE(Log, Http_Hit_Id)> s_HttpHitId
Definition: ncbidiag.cpp:2948
static string s_GetExceptionText(const CException *pex)
Definition: ncbidiag.cpp:7803
static CSafeStatic< NCBI_PARAM_TYPE(Diag, Old_Post_Format)> s_OldPostFormat(CSafeStaticLifeSpan(CSafeStaticLifeSpan::eLifeSpan_Long, 2))
static const char * s_LegacyAppStateStr[]
Definition: ncbidiag.cpp:1216
static void s_UnsetDiagPostFlag(TDiagPostFlags &flags, EDiagPostFlag flag)
Definition: ncbidiag.cpp:6055
string s_ReadString(const char *filename)
Definition: ncbidiag.cpp:3077
void EndmFatal(const CNcbiDiag &diag)
Definition: ncbidiag.cpp:8360
void s_FormatStackTrace(CNcbiOstream &os, const CStackTrace &trace)
Definition: ncbidiag.cpp:5561
static FAbortHandler s_UserAbortHandler
Definition: ncbidiag.cpp:8139
Uint8 s_ParseInt(const string &message, size_t &pos, size_t width, char sep)
Definition: ncbidiag.cpp:4680
static bool s_DiagPostFlagsInitialized
Definition: ncbidiag.cpp:3950
static CSafeStatic< NCBI_PARAM_TYPE(Diag, ErrLog_Rate_Limit)> s_ErrLogRateLimit
Definition: ncbidiag.cpp:353
static const char * kLogName_None
Definition: ncbidiag.cpp:175
static const int kDiagW_Client
Definition: ncbidiag.cpp:3154
static bool s_SplitLogFile
Definition: ncbidiag.cpp:6703
DEFINE_STATIC_MUTEX(s_DiagMutex)
CDiagBuffer & GetDiagBuffer(void)
Definition: ncbidiag.cpp:6353
const CDiagContext::TUID kUID_Mult
Definition: ncbidiag.cpp:1591
bool IsGlobalProperty(const string &name)
Definition: ncbidiag.cpp:1919
static const char * kUnknown_Session
Definition: ncbidiag.cpp:3159
static const Uint8 kOwnerTID_None
Definition: ncbidiag.cpp:1041
static CTime s_GetFastTime(void)
Definition: ncbidiag.cpp:1253
static const int kDiagW_Session
Definition: ncbidiag.cpp:3155
static const char * s_AppStateStr[]
Definition: ncbidiag.cpp:1212
static const char * kUnknown_Client
Definition: ncbidiag.cpp:3158
static const char * kLogName_Tee
Definition: ncbidiag.cpp:181
CTempString s_ParseStr(const string &message, size_t &pos, char sep, bool optional=false)
Definition: ncbidiag.cpp:4711
static const int kDiagW_SN
Definition: ncbidiag.cpp:3151
EDiagAppState s_StrToAppState(const string &state)
Definition: ncbidiag.cpp:1225
static CSafeStatic< NCBI_PARAM_TYPE(Diag, Print_System_TID)> s_PrintSystemTID
Definition: ncbidiag.cpp:273
static CDiagHandler * s_CreateDefaultDiagHandler(void)
Definition: ncbidiag.cpp:4041
EDiagSev AdjustApplogPrintableSeverity(EDiagSev sev)
Definition: ncbidiag.cpp:879
CNcbiIstream & operator>>(CNcbiIstream &in, CLogRateLimit &lim)
Definition: ncbidiag.cpp:320
static CSafeStatic< NCBI_PARAM_TYPE(Diag, Max_Line_Length)> s_MaxLineLength
Definition: ncbidiag.cpp:292
static const int kDiagW_TID
Definition: ncbidiag.cpp:3148
const CDiagContext::TUID kUID_InitBase
Definition: ncbidiag.cpp:1590
static string s_GetLogConfigString(const CTempString name, const CTempString defval, CNcbiRegistry *config)
Definition: ncbidiag.cpp:3509
EDiagMergeLines
Definition: ncbidiag.cpp:5540
@ eDiagMergeLines_Default
Definition: ncbidiag.cpp:5541
@ eDiagMergeLines_On
Definition: ncbidiag.cpp:5543
@ eDiagMergeLines_Off
Definition: ncbidiag.cpp:5542
static const char * kNcbiApplogKeywordStrings[]
Definition: ncbidiag.cpp:2459
static const char * kLogName_Stdout
Definition: ncbidiag.cpp:177
static const char * kDiagTimeFormat
Definition: ncbidiag.cpp:3145
NCBI_PARAM_STATIC_PROXY(CLogRateLimit, CLogRateLimit::TValue)
typedef NCBI_PARAM_TYPE(Diag, Tee_To_Stderr) TTeeToStderr
static const TDiagPostFlags s_DefaultPostFlags
Definition: ncbidiag.cpp:3945
static bool s_FinishedSetupDiag
Definition: ncbidiag.cpp:438
static const int kDiagW_AppState
Definition: ncbidiag.cpp:3150
static CSafeStatic< CAtomicCounter_WithAutoInit > s_ReopenEntered
Definition: ncbidiag.cpp:83
const TDiagPostFlags kApplogDiagPostFlags
Definition: ncbidiag.cpp:2220
static CSafeStatic< NCBI_PARAM_TYPE(Diag, TraceLog_Rate_Limit)> s_TraceLogRateLimit
Definition: ncbidiag.cpp:365
const char * s_AppStateToStr(EDiagAppState state)
Definition: ncbidiag.cpp:1220
static const char * kUnknown_Host
Definition: ncbidiag.cpp:3157
static bool s_GetLogConfigBool(const CTempString name, bool defval, CNcbiRegistry *config)
Definition: ncbidiag.cpp:3524
EThreadDataState
Definition: ncbidiag.cpp:897
@ eInitialized
Definition: ncbidiag.cpp:900
@ eDeinitialized
Definition: ncbidiag.cpp:901
@ eReinitializing
Definition: ncbidiag.cpp:902
@ eUninitialized
Definition: ncbidiag.cpp:898
@ eInitializing
Definition: ncbidiag.cpp:899
static CSafeStatic< NCBI_PARAM_TYPE(Diag, TraceLog_Rate_Period)> s_TraceLogRatePeriod
Definition: ncbidiag.cpp:371
CDiagContext_Extra g_PostPerf(int status, double timespan, SDiagMessage::TExtraArgs &args)
Definition: ncbidiag.cpp:8347
static const int kDiagW_UID
Definition: ncbidiag.cpp:3152
static void s_SetDiagPostFlag(TDiagPostFlags &flags, EDiagPostFlag flag)
Definition: ncbidiag.cpp:6045
static TDiagPostFlags s_SetDiagPostAllFlags(TDiagPostFlags &flags, TDiagPostFlags new_flags)
Definition: ncbidiag.cpp:6029
NCBI_PARAM_ENUM_ARRAY(EDiagSev, Diag, Tee_Min_Severity)
Definition: ncbidiag.cpp:381
const char * str_rev_str(const char *begin_str, const char *end_str, const char *str_search)
Definition: ncbidiag.cpp:615
static CSafeStatic< NCBI_PARAM_TYPE(Log, Http_Session_Id)> s_HttpSessionId
Definition: ncbidiag.cpp:2858
static CSafeStatic< NCBI_PARAM_TYPE(Diag, Log_Size_Limit)> s_LogSizeLimit
Definition: ncbidiag.cpp:286
NCBI_PARAM_DECL(bool, Diag, Old_Post_Format)
void * InitDiagHandler(void)
Definition: ncbidiag.cpp:4000
static const char * kRootLog
Definition: ncbidiag.cpp:3419
CDiagHandler * s_DefaultHandler
Definition: ncbidiag.cpp:4034
static thread_local CDiagContextThreadData * s_ThreadDataCache
Definition: ncbidiag.cpp:908
static CSafeStatic< CDiagFilter > s_PostFilter
Definition: ncbidiag.cpp:609
static CSafeStatic< NCBI_PARAM_TYPE(Diag, Disable_AppLog_Messages)> s_DisableAppLog
Definition: ncbidiag.cpp:435
static CSafeStatic< NCBI_PARAM_TYPE(Diag, ErrLog_Rate_Period)> s_ErrLogRatePeriod
Definition: ncbidiag.cpp:359
static CSafeStatic< unique_ptr< string > > s_HostLocation
Definition: ncbidiag.cpp:3089
static const char * kLogName_Memory
Definition: ncbidiag.cpp:180
static CSafeStatic< unique_ptr< string > > s_HostRole
Definition: ncbidiag.cpp:3088
static const char * kLogName_Unknown
Definition: ncbidiag.cpp:176
static thread_local EThreadDataState s_ThreadDataState(eUninitialized)
string GetDefaultLogLocation(CNcbiApplication &app)
Definition: ncbidiag.cpp:3421
static const char s_ExtraEncodeChars[256][4]
Definition: ncbidiag.cpp:4745
static CSafeStatic< NCBI_PARAM_TYPE(Diag, AutoWrite_Context)> s_AutoWrite_Context
Definition: ncbidiag.cpp:267
static bool s_DiagUseRWLock
Definition: ncbidiag.cpp:79
static const int kDiagW_PID
Definition: ncbidiag.cpp:3147
static CSafeStatic< NCBI_PARAM_TYPE(Log, Hit_Id)> s_HitId
Definition: ncbidiag.cpp:2954
static const char * kExtraTypeArgName
Definition: ncbidiag.cpp:2752
static CSafeStatic< NCBI_PARAM_TYPE(Log, Client_Ip)> s_DefaultClientIp
Definition: ncbidiag.cpp:2929
const EDiagSev kTeeMinSeverityDef
Definition: ncbidiag.cpp:391
bool s_ParseErrCodeInfoStr(string &str, const SIZE_TYPE line, int &x_code, int &x_severity, string &x_message, bool &x_ready)
Definition: ncbidiag.cpp:8200
static CSafeStatic< NCBI_PARAM_TYPE(Diag, AppLog_Rate_Limit)> s_AppLogRateLimit
Definition: ncbidiag.cpp:341
static CSafeStatic< CRWLock > s_DiagRWLock(CSafeStaticLifeSpan(CSafeStaticLifeSpan::eLifeSpan_Long, 1))
NCBI_PARAM_ENUM_DECL(EDiagSev, Diag, Tee_Min_Severity)
static const char * kLogName_Stderr
Definition: ncbidiag.cpp:178
Defines NCBI C++ service classes and functions for diagnostic APIs, classes, and macros.
@ eDiagFilter_Reject
Definition: ncbidiag_p.hpp:56
Defines NCBI C++ exception handling.
Defines classes: CDirEntry, CFile, CDir, CSymLink, CMemoryFile, CFileUtil, CFileLock,...
T min(T x_, T y_)
std::istream & in(std::istream &in_, double &x_)
void abort()
double f(double x_, const double &y_)
Definition: njn_root.hpp:188
static const char * suffix[]
Definition: pcregrep.c:408
static const char * prefix[]
Definition: pcregrep.c:405
Defines CRequestContext class for NCBI C++ diagnostic API.
static CNamedPipeClient * client
#define NcbiSys_getenv
Definition: ncbisys.hpp:90
#define NcbiSys_lseek
Definition: ncbisys.hpp:46
#define NcbiSys_open
Definition: ncbisys.hpp:92
#define NcbiSys_close
Definition: ncbisys.hpp:40
#define NcbiSys_write
Definition: ncbisys.hpp:51
EDiagFileType m_FileType
Definition: ncbidiag.cpp:7172
string * m_Composed
Definition: ncbidiag.cpp:7171
SDiagMessage * m_Message
Definition: ncbidiag.cpp:7170
This class allows to add build info (date and tag) to application version.
Definition: version_api.hpp:62
SDiagErrCodeDescription –.
Definition: ncbidiag.hpp:2994
SDiagMessageData(void)
Definition: ncbidiag.cpp:1286
EDiagAppState m_AppState
Definition: ncbidiag.cpp:1282
CDiagContext::TUID m_UID
Definition: ncbidiag.cpp:1274
~SDiagMessageData(void)
Definition: ncbidiag.cpp:1264
SDiagMessage –.
Definition: ncbidiag.hpp:1599
bool Append(const string &str)
Definition: ncbidiag.cpp:7372
SMessageBuffer(void)
Definition: ncbidiag.cpp:7344
~SMessageBuffer(void)
Definition: ncbidiag.cpp:7354
bool IsEmpty(void)
Definition: ncbidiag.cpp:7361
size_t max_lines
Definition: ncbidiag.cpp:7342
void Clear(void)
Definition: ncbidiag.cpp:7366
TKeywords * Create(void)
Definition: ncbidiag.cpp:2605
unordered_set< string > TKeywords
Definition: ncbidiag.cpp:2603
void Cleanup(TKeywords &)
Definition: ncbidiag.cpp:2615
static atomic< thread::id > sm_ThreadID
Definition: ncbidiag.cpp:4267
static SDiagMessage Report(EDiagSev &sev)
Definition: ncbidiag.cpp:4298
static atomic< bool > sm_Reported
Definition: ncbidiag.cpp:4268
static bool Check()
Definition: ncbidiag.cpp:4276
Definition: type.c:6
Portable system-logging API.
#define _TROUBLE
#define _ASSERT
CRef< CTestThread > thr[k_NumThreadsMax]
Definition: test_mt.cpp:267
else result
Definition: token2.c:20
static wxAcceleratorEntry entries[3]
#define SEEK_CUR
Definition: zconf.h:501
Modified on Tue May 14 16:19:54 2024 by modify_doxy.py rev. 669887