1 /* $Id: logging.cpp 589151 2019-07-08 13:13:17Z 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 * Author: Pavel Ivanov
27 *
28 */
29
30 #include "task_server_pch.hpp"
31
32 // ncbimtx.hpp is needed for proper compilation of ncbifile.hpp
33 #include <corelib/ncbimtx.hpp>
34 #include <corelib/ncbifile.hpp>
35 #include <corelib/request_ctx.hpp>
36 #include <corelib/ncbireg.hpp>
37
38 #include "logging.hpp"
39 #include "threads_man.hpp"
40 #include "memory_man.hpp"
41 #include "server_core.hpp"
42
43 #include <fcntl.h>
44
45
46 BEGIN_NCBI_SCOPE;
47
48 extern CSrvTime s_JiffyTime;
49
50 struct SLogData
51 {
52 char* buf;
53 char* end_ptr;
54 char* cur_ptr;
55 char* cur_msg_ptr;
56 Uint8 post_num;
57 string prefix;
58 string tmp_str;
59 bool has_params;
60 CSrvDiagMsg::ESeverity severity;
61
62 const char* msg_file;
63 const char* msg_func;
64 int msg_line;
65 int err_code;
66 int err_subcode;
67 int last_flush_time;
68
SLogDataSLogData69 SLogData(void)
70 : buf(0), end_ptr(0), cur_ptr(0), cur_msg_ptr(0), post_num(0),
71 has_params(false), severity(CSrvDiagMsg::Trace), msg_file(0), msg_func(0),
72 msg_line(0), err_code(0), err_subcode(0), last_flush_time(0)
73 {
74 }
75 };
76
77
78 class CLogWriter : public CSrvTask
79 {
80 public:
81 CLogWriter(void);
82 virtual ~CLogWriter(void);
83
84 private:
85 virtual void ExecuteSlice(TSrvThreadNum thr_num);
86 };
87
88
89 static CSrvDiagMsg::ESeverity s_VisibleSev = CSrvDiagMsg::Warning;
90 static bool s_LogRequests = true;
91 static string s_UnkClient = "UNK_CLIENT";
92 static string s_UnkSession = "UNK_SESSION";
93 static const char* s_SevNames[] = {"Trace", "Info", "Warning", "Error", "Critical", "Fatal", "Fatal", NULL};
94 static const char* s_SoftFatalActions[] = {"abort", "shutdown", "log", NULL};
95 static int s_SoftFatal = 0;
96 static const size_t kOneRecReserve = 500;
97 static const size_t kInitLogBufSize = 10000000;
98 static size_t s_LogBufSize = kInitLogBufSize;
99 static int s_MaxFlushPeriod = 60;
100 static int s_FileReopenPeriod = 60;
101 static Uint8 s_LongCmd = 30000000;
102 static string s_CmdLine;
103 static string s_Pid;
104 static string s_AppUID;
105 static string s_FileName;
106 static Uint8 s_ProcessPostNum = 0;
107 static SLogData* s_MainData = NULL;
108 static bool s_InApplog = false;
109 static CMiniMutex s_WriteQueueLock;
110 static list<CTempString> s_WriteQueue;
111 static CLogWriter* s_LogWriter = NULL;
112 static int s_LogFd = -1;
113 static int s_LastReopenTime = 0;
114 static bool s_NeedFatalHalt = false;
115 static bool s_FileNameInitialized = false;
116 static bool s_ThreadsStarted = false;
117 static bool s_DiskSpaceAlert = false;
118 static CFutex s_CntHaltedThreads;
119 static CFutex s_Halt;
120
121 extern string s_AppBaseName;
122 extern SSrvThread** s_Threads;
123
124
125
Logging_DiskSpaceAlert(void)126 void Logging_DiskSpaceAlert(void)
127 {
128 s_DiskSpaceAlert = true;
129 }
130
131 void
SaveAppCmdLine(const string & cmd_line)132 SaveAppCmdLine(const string& cmd_line)
133 {
134 s_CmdLine = cmd_line;
135 }
136
137 void
SetLogFileName(CTempString name)138 SetLogFileName(CTempString name)
139 {
140 s_FileName = name;
141 if (!CDirEntry::IsAbsolutePath(s_FileName)) {
142 s_FileName = CDirEntry::NormalizePath(CDirEntry::ConcatPath(CDir::GetCwd(), s_FileName));
143 }
144 }
145
GetLogFileName(void)146 string GetLogFileName(void)
147 {
148 return s_FileName;
149 }
150
GetLogVisibility(void)151 string GetLogVisibility(void)
152 {
153 return s_SevNames[s_VisibleSev];
154 }
155
GetSoftFatalAction(void)156 string GetSoftFatalAction(void)
157 {
158 return s_SoftFatalActions[s_SoftFatal];
159 }
160
161 static void
s_InitConstants(void)162 s_InitConstants(void)
163 {
164 Int8 pid = CCurrentProcess::GetPid();
165 time_t t = time(0);
166 const string& host = CTaskServer::GetHostName();
167 Int8 h = 212;
168 ITERATE(string, s, host) {
169 h = h*1265 + *s;
170 }
171 h &= 0xFFFF;
172 // The low 4 bits are reserved as GUID generator version number.
173 Int8 uid = (h << 48) |
174 ((pid & 0xFFFF) << 32) |
175 ((Int8(t) & 0xFFFFFFF) << 4) |
176 1; // version #1 - fixed type conversion bug
177
178 s_AppUID = NStr::UInt8ToString(Uint8(uid), 0, 16);
179 if (s_AppUID.size() != 16)
180 s_AppUID.insert(s_AppUID.begin(), 16 - s_AppUID.size(), '0');
181 s_Pid = NStr::UInt8ToString(Uint8(pid));
182 if (s_Pid.size() < 5)
183 s_Pid.insert(s_Pid.begin(), 5 - s_Pid.size(), '0');
184 }
185
186 static inline void
s_OpenLogFile(void)187 s_OpenLogFile(void)
188 {
189 #ifdef NCBI_OS_LINUX
190 if (s_DiskSpaceAlert) {
191 s_DiskSpaceAlert = false;
192 unlink(s_FileName.c_str());
193 }
194 s_LogFd = open(s_FileName.c_str(), O_WRONLY | O_APPEND | O_CREAT,
195 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
196 #endif
197 }
198
199 static void
s_WriteLog(const char * buf,size_t size)200 s_WriteLog(const char* buf, size_t size)
201 {
202 if (!buf) {
203 return;
204 }
205 if (s_LogFd == -1) {
206 s_OpenLogFile();
207 if (s_LogFd == -1)
208 return;
209 s_LastReopenTime = CSrvTime::CurSecs();
210 }
211
212 #ifdef NCBI_OS_LINUX
213 if (write(s_LogFd, buf, size) != ssize_t(size)) {
214 // There's nothing we can do about it here
215 }
216 #endif
217 }
218
219 static void
s_QueueLogWrite(char * buf,size_t size)220 s_QueueLogWrite(char* buf, size_t size)
221 {
222 if (!buf) {
223 return;
224 }
225 s_WriteQueueLock.Lock();
226 bool need_signal = s_WriteQueue.empty();
227 s_WriteQueue.push_back(CTempString(buf, size));
228 s_WriteQueueLock.Unlock();
229
230 if (need_signal)
231 s_LogWriter->SetRunnable();
232 }
233
234 static inline void
s_AllocNewBuf(SLogData * data,size_t buf_size)235 s_AllocNewBuf(SLogData* data, size_t buf_size)
236 {
237 data->buf = (char*)malloc(buf_size);
238 data->cur_ptr = data->cur_msg_ptr = data->buf;
239 data->end_ptr = data->buf ? data->buf + buf_size - 8 : data->buf;
240 }
241
242 static void
s_RotateLogBuf(SLogData * data)243 s_RotateLogBuf(SLogData* data)
244 {
245 char* old_buf = data->buf;
246 char* old_msg_ptr = data->cur_msg_ptr;
247 size_t old_msg_size = data->cur_ptr - data->cur_msg_ptr;
248 s_AllocNewBuf(data, s_LogBufSize);
249 if (old_msg_size != 0 && data->buf) {
250 memcpy(data->buf, old_msg_ptr, old_msg_size);
251 data->cur_ptr += old_msg_size;
252 }
253 s_QueueLogWrite(old_buf, old_msg_ptr - old_buf);
254 data->last_flush_time = CSrvTime::CurSecs();
255 }
256
257 static inline void
s_InitLogPrefix(SLogData * data,TSrvThreadNum thr_num)258 s_InitLogPrefix(SLogData* data, TSrvThreadNum thr_num)
259 {
260 data->prefix.assign(s_Pid);
261 data->prefix.append(1, '/');
262 NStr::UInt8ToString(data->tmp_str, thr_num);
263 if (data->tmp_str.size() < 3)
264 data->prefix.append(3 - data->tmp_str.size(), '0');
265 data->prefix.append(data->tmp_str.data(), data->tmp_str.size());
266 data->prefix.append(1, '/');
267 }
268
269 static inline bool
s_CheckBufSize(SLogData * data,size_t need_size)270 s_CheckBufSize(SLogData* data, size_t need_size)
271 {
272 if (data->cur_ptr + need_size >= data->end_ptr)
273 s_RotateLogBuf(data);
274 return data->buf != nullptr;
275 }
276
277 static inline void
s_AddToLog(SLogData * data,const char * str,size_t size)278 s_AddToLog(SLogData* data, const char* str, size_t size)
279 {
280 if (s_CheckBufSize(data, size)) {
281 memcpy(data->cur_ptr, str, size);
282 data->cur_ptr += size;
283 }
284 }
285
286 static inline void
s_AddToLogStripLF(SLogData * data,const char * str,size_t size)287 s_AddToLogStripLF(SLogData* data, const char* str, size_t size)
288 {
289 if (s_CheckBufSize(data, size)) {
290 for (; size != 0; --size, ++str) {
291 char c = *str;
292 *data->cur_ptr++ = c == '\n'? ';': c;
293 }
294 }
295 }
296
297 static inline void
s_AddToLog(SLogData * data,const char * str)298 s_AddToLog(SLogData* data, const char* str)
299 {
300 s_AddToLog(data, str, strlen(str));
301 }
302
303 static inline void
s_AddToLogStripLF(SLogData * data,const char * str)304 s_AddToLogStripLF(SLogData* data, const char* str)
305 {
306 s_AddToLogStripLF(data, str, strlen(str));
307 }
308
309 static inline void
s_AddToLog(SLogData * data,const string & str)310 s_AddToLog(SLogData* data, const string& str)
311 {
312 s_AddToLog(data, str.data(), str.size());
313 }
314
315 static inline void
s_AddToLogStripLF(SLogData * data,const string & str)316 s_AddToLogStripLF(SLogData* data, const string& str)
317 {
318 s_AddToLogStripLF(data, str.data(), str.size());
319 }
320
321 static inline void
s_AddToLog(SLogData * data,const string & str,Uint1 min_chars)322 s_AddToLog(SLogData* data, const string& str, Uint1 min_chars)
323 {
324 if (s_CheckBufSize(data, max(str.size(), size_t(min_chars)))) {
325 s_AddToLog(data, str.data(), str.size());
326 for (Uint1 i = min_chars; i > str.size(); --i)
327 *data->cur_ptr++ = ' ';
328 }
329 }
330
331 static inline void
s_AddToLog(SLogData * data,Uint8 num)332 s_AddToLog(SLogData* data, Uint8 num)
333 {
334 NStr::UInt8ToString(data->tmp_str, num);
335 s_AddToLog(data, data->tmp_str);
336 }
337
338 static inline void
s_AddToLog(SLogData * data,Int8 num)339 s_AddToLog(SLogData* data, Int8 num)
340 {
341 NStr::Int8ToString(data->tmp_str, num);
342 s_AddToLog(data, data->tmp_str);
343 }
344
345 static inline void
s_AddToLog(SLogData * data,int num)346 s_AddToLog(SLogData* data, int num)
347 {
348 s_AddToLog(data, Uint8(num));
349 }
350
351 static inline void
s_AddToLog(SLogData * data,Uint8 num,Uint1 min_digs)352 s_AddToLog(SLogData* data, Uint8 num, Uint1 min_digs)
353 {
354 NStr::UInt8ToString(data->tmp_str, num);
355 if (s_CheckBufSize(data, max(data->tmp_str.size(), size_t(min_digs)))) {
356 for (Uint1 i = min_digs; i > data->tmp_str.size(); --i)
357 *data->cur_ptr++ = '0';
358 s_AddToLog(data, data->tmp_str);
359 }
360 }
361
362 static inline void
s_AddToLog(SLogData * data,double num)363 s_AddToLog(SLogData* data, double num)
364 {
365 NStr::DoubleToString(data->tmp_str, num);
366 s_AddToLog(data, data->tmp_str);
367 }
368
369 static void
s_AddLogPrefix(SSrvThread * thr,SLogData * data,CRequestContext * diag_ctx=NULL)370 s_AddLogPrefix(SSrvThread* thr, SLogData* data, CRequestContext* diag_ctx = NULL)
371 {
372 if (!data->buf) {
373 return;
374 }
375 s_AddToLog(data, data->prefix);
376 if (!diag_ctx && thr && thr->cur_task)
377 diag_ctx = thr->cur_task->m_DiagCtx;
378
379 Uint8 req_id = diag_ctx? diag_ctx->GetRequestID()
380 : CRequestContext::GetNextRequestID();
381 s_AddToLog(data, req_id, 4);
382 s_AddToLog(data, "/A ");
383
384 s_AddToLog(data, s_AppUID);
385 *data->cur_ptr++ = ' ';
386
387 Uint8 proc_post_num = AtomicAdd(s_ProcessPostNum, 1);
388 s_AddToLog(data, proc_post_num, 4);
389 *data->cur_ptr++ = '/';
390 s_AddToLog(data, ++data->post_num, 4);
391 *data->cur_ptr++ = ' ';
392
393 CSrvTime cur_time = CSrvTime::Current();
394 if (!s_CheckBufSize(data, 50)) {
395 return;
396 }
397 Uint1 len = cur_time.Print(data->cur_ptr, CSrvTime::eFmtLogging);
398 data->cur_ptr += len;
399 *data->cur_ptr++ = ' ';
400
401 s_AddToLog(data, CTaskServer::GetHostName(), 15);
402 *data->cur_ptr++ = ' ';
403
404 string str = diag_ctx? diag_ctx->GetClientIP(): s_UnkClient;
405 if (str.empty())
406 str = s_UnkClient;
407 s_AddToLog(data, str, 15);
408 *data->cur_ptr++ = ' ';
409
410 str = diag_ctx? diag_ctx->GetSessionID(): s_UnkSession;
411 if (str.empty())
412 str = s_UnkSession;
413 s_AddToLog(data, str, 24);
414 *data->cur_ptr++ = ' ';
415
416 s_AddToLog(data, s_AppBaseName);
417 *data->cur_ptr++ = ' ';
418 }
419
420 static void
s_AddParamName(SLogData * data,CTempString name)421 s_AddParamName(SLogData* data, CTempString name)
422 {
423 if (!s_CheckBufSize(data, name.size() + 2)) {
424 return;
425 }
426 if (data->has_params)
427 *data->cur_ptr++ = '&';
428 else
429 data->has_params = true;
430 s_AddToLog(data, name.data(), name.size());
431 *data->cur_ptr++ = '=';
432 }
433
434 static SLogData*
s_AllocNewData(TSrvThreadNum thr_num)435 s_AllocNewData(TSrvThreadNum thr_num)
436 {
437 SLogData* data = new SLogData;
438 data->post_num = 0;
439 data->last_flush_time = 0;
440 s_AllocNewBuf(data, s_LogBufSize);
441 s_InitLogPrefix(data, thr_num);
442 return data;
443 }
444
445 static void
s_AllocMainData(void)446 s_AllocMainData(void)
447 {
448 s_InitConstants();
449 s_MainData = s_AllocNewData(0);
450 s_AddLogPrefix(NULL, s_MainData);
451 s_AddToLog(s_MainData, "start ");
452 s_AddToLog(s_MainData, s_CmdLine);
453 *s_MainData->cur_ptr++ = '\n';
454 s_MainData->cur_msg_ptr = s_MainData->cur_ptr;
455 }
456
457 static void
s_InitFileName(void)458 s_InitFileName(void)
459 {
460 if (s_FileName.empty()) {
461 s_FileName = CDirEntry::MakePath("/log/srv", s_AppBaseName, "log");
462 s_OpenLogFile();
463 if (s_LogFd == -1)
464 s_FileName = CDirEntry::MakePath(kEmptyStr, s_AppBaseName, "log");
465 else
466 s_InApplog = true;
467 }
468 s_FileNameInitialized = true;
469 }
470
471 NCBI_NORETURN static void
s_DoFatalAbort(SLogData * data)472 s_DoFatalAbort(SLogData* data)
473 {
474 s_NeedFatalHalt = true;
475 #if 1
476 int cnt_halted = s_CntHaltedThreads.AddValue(1);
477 int cnt_need = GetCntRunningThreads() + 2;
478 if (!s_ThreadsStarted)
479 cnt_need = 1;
480 for (int attempt=0; attempt<500 && cnt_halted != cnt_need; ++attempt) {
481 s_CntHaltedThreads.WaitValueChange(cnt_halted, s_JiffyTime);
482 cnt_halted = s_CntHaltedThreads.GetValue();
483 // In a very rare situation CntRunningThreads can change here
484 cnt_need = GetCntRunningThreads() + 2;
485 }
486 #endif
487 if (!s_FileNameInitialized)
488 s_InitFileName();
489 ITERATE(list<CTempString>, it, s_WriteQueue) {
490 CTempString str = *it;
491 s_WriteLog(str.data(), str.size());
492 }
493 if (data->cur_ptr != data->buf)
494 s_WriteLog(data->buf, data->cur_ptr - data->buf);
495
496 #ifdef NCBI_OS_LINUX
497 close(s_LogFd);
498 #endif
499 abort();
500 }
501
502 static inline void
s_CheckFatalAbort(void)503 s_CheckFatalAbort(void)
504 {
505 if (!s_NeedFatalHalt)
506 return;
507
508 SLogData* data = GetCurThread()->log_data;
509 if (data->cur_ptr != data->buf)
510 s_QueueLogWrite(data->buf, data->cur_ptr - data->buf);
511 s_CntHaltedThreads.AddValue(1);
512 s_CntHaltedThreads.WakeUpWaiters(1);
513 s_Halt.WaitValueChange(0);
514 }
515
516 void
LogNoteThreadsStarted(void)517 LogNoteThreadsStarted(void)
518 {
519 s_ThreadsStarted = true;
520 s_RotateLogBuf(s_MainData);
521 }
522
523 void
ConfigureLogging(const CNcbiRegistry * reg,CTempString section)524 ConfigureLogging(const CNcbiRegistry* reg, CTempString section)
525 {
526 s_LogRequests = reg->GetBool(section, "log_requests", true);
527 s_LogBufSize = NStr::StringToUInt8_DataSize(
528 reg->GetString(section, "log_thread_buf_size", "10 MB"));
529 s_MaxFlushPeriod = reg->GetInt(section, "log_flush_period", 60);
530 s_FileReopenPeriod = reg->GetInt(section, "log_reopen_period", 60);
531 string vis = reg->GetString(section, "log_visible", "Warning");
532 size_t i = 0;
533 for (i = 0; s_SevNames[i] != NULL; ++i) {
534 if (vis.compare(s_SevNames[i]) == 0) {
535 s_VisibleSev = (CSrvDiagMsg::ESeverity)i;
536 break;
537 }
538 }
539 string tmp = reg->GetString(section, "soft_fatal_action", "abort");
540 for (i = 0; s_SoftFatalActions[i] != NULL; ++i) {
541 if (tmp.compare(s_SoftFatalActions[i]) == 0) {
542 s_SoftFatal = i;
543 break;
544 }
545 }
546 s_LongCmd = Uint8(reg->GetInt(section, "log_long_cmd_after", 30000)) * kUSecsPerMSec;
547 }
548
ReConfig_Logging(const CTempString & section,const CNcbiRegistry & new_reg,string &)549 bool ReConfig_Logging(const CTempString& section, const CNcbiRegistry& new_reg, string& /*err_message*/)
550 {
551 ConfigureLogging(&new_reg, section);
552 return true;
553 }
554
IsLongCommand(Uint8 cmd_len)555 bool IsLongCommand(Uint8 cmd_len)
556 {
557 return cmd_len >= s_LongCmd;
558 }
559
WriteSetup_Logging(CSrvSocketTask & task)560 void WriteSetup_Logging(CSrvSocketTask& task)
561 {
562 string is("\": "), iss("\": \""), eol(",\n\"");
563 task.WriteText(eol).WriteText("log_requests").WriteText(is ).WriteBool( s_LogRequests);
564 task.WriteText(eol).WriteText("log_thread_buf_size").WriteText(is ).WriteNumber( s_LogBufSize);
565 task.WriteText(eol).WriteText("log_flush_period").WriteText(is ).WriteNumber( s_MaxFlushPeriod);
566 task.WriteText(eol).WriteText("log_reopen_period").WriteText(is ).WriteNumber( s_FileReopenPeriod);
567 task.WriteText(eol).WriteText("log_visible").WriteText(iss).WriteText(GetLogVisibility()).WriteText("\"");
568 task.WriteText(eol).WriteText("soft_fatal_action").WriteText(iss).WriteText(GetSoftFatalAction()).WriteText("\"");
569 task.WriteText(eol).WriteText("log_long_cmd_after").WriteText(is).WriteNumber( s_LongCmd / kUSecsPerMSec);
570 }
571
572 void
InitLogging(void)573 InitLogging(void)
574 {
575 if (!s_MainData)
576 s_AllocMainData();
577
578 s_InitFileName();
579 s_LogWriter = new CLogWriter();
580 }
581
582 void
FinalizeLogging(void)583 FinalizeLogging(void)
584 {
585 if (s_MainData->cur_ptr != s_MainData->buf) {
586 s_WriteLog(s_MainData->buf, s_MainData->cur_ptr - s_MainData->buf);
587 s_MainData->cur_ptr = s_MainData->buf;
588 }
589
590 s_AddLogPrefix(NULL, s_MainData);
591 s_AddToLog(s_MainData, "stop 0 ");
592 CSrvTime cur_time = CSrvTime::Current();
593 cur_time -= CTaskServer::GetStartTime();
594 s_AddToLog(s_MainData, cur_time.Sec());
595 *s_MainData->cur_ptr++ = '.';
596 s_AddToLog(s_MainData, cur_time.NSec(), 9);
597 *s_MainData->cur_ptr++ = '\n';
598 s_WriteLog(s_MainData->buf, s_MainData->cur_ptr - s_MainData->buf);
599
600 #ifdef NCBI_OS_LINUX
601 close(s_LogFd);
602 #endif
603 }
604
605 void
AssignThreadLogging(SSrvThread * thr)606 AssignThreadLogging(SSrvThread* thr)
607 {
608 if (thr->thread_num == 0) {
609 if (!s_MainData)
610 s_AllocMainData();
611 thr->log_data = s_MainData;
612 }
613 else {
614 thr->log_data = s_AllocNewData(thr->thread_num);
615 }
616 }
617
618 void
CheckLoggingFlush(SSrvThread * thr)619 CheckLoggingFlush(SSrvThread* thr)
620 {
621 s_CheckFatalAbort();
622
623 SLogData* data = thr->log_data;
624 int cur_time = CSrvTime::CurSecs();
625 if (cur_time - data->last_flush_time < s_MaxFlushPeriod)
626 return;
627
628 if (data->buf && data->cur_ptr == data->buf)
629 data->last_flush_time = cur_time;
630 else
631 s_RotateLogBuf(data);
632 }
633
634 void
StartThreadLogging(SSrvThread * thr)635 StartThreadLogging(SSrvThread* thr)
636 {
637 thr->log_data = s_AllocNewData(thr->thread_num);
638 }
639
640 void
StopThreadLogging(SSrvThread * thr)641 StopThreadLogging(SSrvThread* thr)
642 {
643 SLogData* data = thr->log_data;
644 if (data->cur_ptr != data->buf)
645 s_QueueLogWrite(data->buf, data->cur_ptr - data->buf);
646 else if (data->buf)
647 free(data->buf);
648 delete data;
649 s_CheckFatalAbort();
650 }
651
652 void
ReleaseThreadLogging(SSrvThread * thr)653 ReleaseThreadLogging(SSrvThread* thr)
654 {
655 SLogData* data = thr->log_data;
656 if (data->cur_ptr != data->buf) {
657 s_WriteLog(data->buf, data->cur_ptr - data->buf);
658 data->cur_ptr = data->buf;
659 }
660 }
661
662 static const char*
find_match(char lsep,char rsep,const char * start,const char * stop)663 find_match(char lsep, char rsep, const char* start, const char* stop)
664 {
665 if (*(stop - 1) != rsep) return stop;
666 int balance = 1;
667 const char* pos = stop - 2;
668 for (; pos > start; pos--) {
669 if (*pos == rsep) {
670 balance++;
671 }
672 else if (*pos == lsep) {
673 if (--balance == 0) break;
674 }
675 }
676 return (pos <= start) ? NULL : pos;
677 }
678
679 static const char*
str_rev_str(const char * begin_str,const char * end_str,const char * str_search)680 str_rev_str(const char* begin_str, const char* end_str, const char* str_search)
681 {
682 if (begin_str == NULL)
683 return NULL;
684 if (end_str == NULL)
685 return NULL;
686 if (str_search == NULL)
687 return NULL;
688
689 const char* search_char = str_search + strlen(str_search);
690 const char* cur_char = end_str;
691
692 do {
693 --search_char;
694 do {
695 --cur_char;
696 } while(*cur_char != *search_char && cur_char != begin_str);
697 if (*cur_char != *search_char)
698 return NULL;
699 }
700 while (search_char != str_search);
701
702 return cur_char;
703 }
704
705 static void
s_ParseFuncName(const char * func,CTempString & class_name,CTempString & func_name)706 s_ParseFuncName(const char* func, CTempString& class_name, CTempString& func_name)
707 {
708 if (!func || *func == '\0')
709 return;
710
711 // Skip function arguments
712 size_t len = strlen(func);
713 const char* end_str = find_match('(', ')',
714 func,
715 func + len);
716 if (end_str == func + len) {
717 // Missing '('
718 return;
719 }
720 if (end_str) {
721 // Skip template arguments
722 end_str = find_match('<', '>', func, end_str);
723 }
724 if (!end_str)
725 return;
726 // Get a function/method name
727 const char* start_str = NULL;
728
729 // Get a function start position.
730 const char* start_str_tmp = str_rev_str(func, end_str, "::");
731 bool has_class = start_str_tmp != NULL;
732 if (start_str_tmp != NULL) {
733 start_str = start_str_tmp + 2;
734 } else {
735 start_str_tmp = str_rev_str(func, end_str, " ");
736 if (start_str_tmp != NULL) {
737 start_str = start_str_tmp + 1;
738 }
739 }
740
741 const char* cur_funct_name = (start_str == NULL? func: start_str);
742 size_t cur_funct_name_len = end_str - cur_funct_name;
743 func_name.assign(cur_funct_name, cur_funct_name_len);
744
745 // Get a class name
746 if (has_class) {
747 end_str = find_match('<', '>', func, start_str - 2);
748 start_str = str_rev_str(func, end_str, " ");
749 const char* cur_class_name = (start_str == NULL? func: start_str + 1);
750 size_t cur_class_name_len = end_str - cur_class_name;
751 class_name.assign(cur_class_name, cur_class_name_len);
752 }
753 }
754
755 static inline bool
s_CheckOldStyleStart(const CSrvDiagMsg * msg)756 s_CheckOldStyleStart(const CSrvDiagMsg* msg)
757 {
758 SLogData* data = msg->m_Data;
759 if (!CSrvDiagMsg::IsSeverityVisible(data->severity))
760 return false;
761 if (data->cur_msg_ptr == data->cur_ptr) {
762 if (msg->m_OldStyle) {
763 msg->StartSrvLog(data->severity, data->msg_file,
764 data->msg_line, data->msg_func);
765 }
766 else {
767 SRV_FATAL("Unrecognized CSrvDiagMsg style");
768 }
769 }
770 return true;
771 }
772
773 static inline CSrvDiagMsg::ESeverity
s_ConvertSeverity(EOldStyleSeverity sev)774 s_ConvertSeverity(EOldStyleSeverity sev)
775 {
776 switch (sev) {
777 case Trace:
778 return CSrvDiagMsg::Trace;
779 case Info:
780 return CSrvDiagMsg::Info;
781 case Warning:
782 return CSrvDiagMsg::Warning;
783 case Error:
784 return CSrvDiagMsg::Error;
785 case Critical:
786 return CSrvDiagMsg::Critical;
787 case Fatal:
788 return CSrvDiagMsg::Fatal;
789 default:
790 SRV_FATAL("Unsupported severity: " << sev);
791 }
792 return CSrvDiagMsg::Trace;
793 }
794
795 static inline CSrvDiagMsg::ESeverity
s_ConvertSeverity(EDiagSev sev)796 s_ConvertSeverity(EDiagSev sev)
797 {
798 switch (sev) {
799 case eDiag_Trace:
800 return CSrvDiagMsg::Trace;
801 case eDiag_Info:
802 return CSrvDiagMsg::Info;
803 case eDiag_Warning:
804 return CSrvDiagMsg::Warning;
805 case eDiag_Error:
806 return CSrvDiagMsg::Error;
807 case eDiag_Critical:
808 return CSrvDiagMsg::Critical;
809 case eDiag_Fatal:
810 return CSrvDiagMsg::Fatal;
811 default:
812 SRV_FATAL("Unsupported severity: " << sev);
813 }
814 return CSrvDiagMsg::Trace;
815 }
816
817 CDiagContext&
GetDiagContext(void)818 GetDiagContext(void)
819 {
820 static CDiagContext ctx;
821 return ctx;
822 }
823
UpdateOnFork(TOnForkFlags)824 void CDiagContext::UpdateOnFork(TOnForkFlags /*flags*/)
825 {
826 CDiagContext::UpdatePID();
827 }
828
829 void
UpdatePID(void)830 CDiagContext::UpdatePID(void)
831 {
832 string old_uid = s_AppUID;
833 s_InitConstants();
834 if (s_Threads) {
835 for (TSrvThreadNum i = 0; i <= s_MaxRunningThreads + 1; ++i) {
836 SSrvThread* thr = s_Threads[i];
837 if (thr)
838 s_InitLogPrefix(thr->log_data, thr->thread_num);
839 }
840 }
841 else if (s_MainData) {
842 s_InitLogPrefix(s_MainData, 0);
843 }
844 CSrvDiagMsg().PrintExtra(NULL)
845 .PrintParam("action", "fork")
846 .PrintParam("parent_guid", old_uid);
847 }
848
849 void
StartCtxRequest(CRequestContext * ctx)850 CDiagContext::StartCtxRequest(CRequestContext* ctx)
851 {
852 ctx->StartRequest();
853 }
854
855 void
StopCtxRequest(CRequestContext * ctx)856 CDiagContext::StopCtxRequest(CRequestContext* ctx)
857 {
858 ctx->StopRequest();
859 }
860
861 bool
IsCtxRunning(CRequestContext * ctx)862 CDiagContext::IsCtxRunning(CRequestContext* ctx)
863 {
864 return ctx->IsRunning();
865 }
866
867 const string&
GetDefaultSessionID(void)868 CDiagContext::GetDefaultSessionID(void)
869 {
870 return kEmptyStr;
871 }
872
873 const string&
GetEncodedSessionID(void)874 CDiagContext::GetEncodedSessionID(void)
875 {
876 return kEmptyStr;
877 }
878
879
CSrvDiagMsg(void)880 CSrvDiagMsg::CSrvDiagMsg(void)
881 : m_Thr(GetCurThread()),
882 m_Data(NULL),
883 m_OldStyle(false)
884 {
885 if (m_Thr) {
886 m_Data = m_Thr->log_data;
887 s_CheckFatalAbort();
888 }
889 else {
890 if (!s_MainData)
891 s_AllocMainData();
892 m_Data = s_MainData;
893 }
894 }
895
~CSrvDiagMsg(void)896 CSrvDiagMsg::~CSrvDiagMsg(void)
897 {
898 if (m_Data->cur_msg_ptr != m_Data->cur_ptr)
899 Flush();
900 }
901
902 bool
IsSeverityVisible(ESeverity sev)903 CSrvDiagMsg::IsSeverityVisible(ESeverity sev)
904 {
905 return int(sev) >= int(s_VisibleSev);
906 }
907
908 const CSrvDiagMsg&
StartSrvLog(ESeverity sev,const char * file,int line,const char * func) const909 CSrvDiagMsg::StartSrvLog(ESeverity sev,
910 const char* file,
911 int line,
912 const char* func) const
913 {
914 if (m_Data->cur_msg_ptr != m_Data->cur_ptr
915 /* && *m_Data->cur_ptr != '\n' */) {
916 *m_Data->cur_ptr++ = '\n';
917 }
918 m_Data->severity = sev;
919 s_AddLogPrefix(m_Thr, m_Data);
920 s_AddToLog(m_Data, s_SevNames[int(sev)]);
921 if (m_OldStyle) {
922 s_AddToLog(m_Data, ": ");
923 if (m_Data->err_code != 0 || m_Data->err_subcode != 0) {
924 s_AddToLog(m_Data, "(");
925 s_AddToLog(m_Data, m_Data->err_code);
926 s_AddToLog(m_Data, ".");
927 s_AddToLog(m_Data, m_Data->err_subcode);
928 s_AddToLog(m_Data, ")");
929 }
930 s_AddToLog(m_Data, " \"");
931 }
932 else {
933 s_AddToLog(m_Data, ": \"");
934 }
935 const char* file_name;
936 size_t name_size;
937 ExtractFileName(file, file_name, name_size);
938 s_AddToLog(m_Data, file_name, name_size);
939 s_AddToLog(m_Data, "\", line ");
940 s_AddToLog(m_Data, line);
941 s_AddToLog(m_Data, ": ");
942 CTempString class_name, func_name;
943 s_ParseFuncName(func, class_name, func_name);
944 s_AddToLog(m_Data, class_name);
945 s_AddToLog(m_Data, "::");
946 s_AddToLog(m_Data, func_name);
947 s_AddToLog(m_Data, "() --- ");
948
949 return *this;
950 }
951
952 const CSrvDiagMsg&
StartInfo(void) const953 CSrvDiagMsg::StartInfo(void) const
954 {
955 CRequestContext* ctx = NULL;
956 if (m_Thr->cur_task)
957 ctx = m_Thr->cur_task->m_DiagCtx;
958 return StartInfo(ctx);
959 }
960
961 const CSrvDiagMsg&
StartInfo(CRequestContext * ctx) const962 CSrvDiagMsg::StartInfo(CRequestContext* ctx) const
963 {
964 m_Data->severity = Warning;
965 s_AddLogPrefix(m_Thr, m_Data, ctx);
966 s_AddToLog(m_Data, "Message[W]: \"UNK_FILE\", line 0: UNK_FUNC --- ");
967 return *this;
968 }
969
970 const CSrvDiagMsg&
StartOldStyle(const char * file,int line,const char * func)971 CSrvDiagMsg::StartOldStyle(const char* file, int line, const char* func)
972 {
973 m_OldStyle = true;
974 m_Data->severity = CSrvDiagMsg::Error;
975 m_Data->msg_file = file;
976 m_Data->msg_func = func;
977 m_Data->msg_line = line;
978 m_Data->err_code = m_Data->err_subcode = 0;
979 return *this;
980 }
981
982 const CSrvDiagMsg&
operator <<(const CSrvDiagMsg & msg,EOldStyleSeverity sev)983 operator<< (const CSrvDiagMsg& msg, EOldStyleSeverity sev)
984 {
985 msg.m_Data->severity = s_ConvertSeverity(sev);
986 return msg;
987 }
988
989 const CSrvDiagMsg&
operator <<(const CSrvDiagMsg & msg,ErrCode err_code)990 operator<< (const CSrvDiagMsg& msg, ErrCode err_code)
991 {
992 msg.m_Data->err_code = err_code.m_Code;
993 msg.m_Data->err_subcode = err_code.m_SubCode;
994 return msg;
995 }
996
997 CSrvDiagMsg&
StartRequest(void)998 CSrvDiagMsg::StartRequest(void)
999 {
1000 return StartRequest(m_Thr->cur_task->m_DiagCtx);
1001 }
1002
1003 CSrvDiagMsg&
StartRequest(CRequestContext * ctx)1004 CSrvDiagMsg::StartRequest(CRequestContext* ctx)
1005 {
1006 if (CDiagContext::IsCtxRunning(ctx)) {
1007 SRV_FATAL("Unexpected StartRequest call");
1008 }
1009 CDiagContext::StartCtxRequest(ctx);
1010 ctx->SetRequestStatus(200);
1011
1012 if (!s_LogRequests)
1013 return *this;
1014
1015 s_AddLogPrefix(m_Thr, m_Data, ctx);
1016 s_AddToLog(m_Data, "request-start ");
1017 m_Data->has_params = false;
1018
1019 return *this;
1020 }
1021
1022 CSrvDiagMsg&
PrintExtra(void)1023 CSrvDiagMsg::PrintExtra(void)
1024 {
1025 return PrintExtra(m_Thr->cur_task->m_DiagCtx);
1026 }
1027
1028 CSrvDiagMsg&
PrintExtra(CRequestContext * ctx)1029 CSrvDiagMsg::PrintExtra(CRequestContext* ctx)
1030 {
1031 if (s_LogRequests) {
1032 s_AddLogPrefix(m_Thr, m_Data, ctx);
1033 s_AddToLog(m_Data, "extra ");
1034 m_Data->has_params = false;
1035 }
1036 return *this;
1037 }
1038
1039 CSrvDiagMsg&
PrintParam(CTempString name,CTempString value)1040 CSrvDiagMsg::PrintParam(CTempString name, CTempString value)
1041 {
1042 if (!s_LogRequests)
1043 return *this;
1044
1045 s_AddParamName(m_Data, name);
1046 if (NStr::NeedsURLEncoding(value))
1047 s_AddToLog(m_Data, NStr::URLEncode(value));
1048 else
1049 s_AddToLog(m_Data, value);
1050 return *this;
1051 }
1052
1053 CSrvDiagMsg&
PrintParam(CTempString name,Int8 value)1054 CSrvDiagMsg::PrintParam(CTempString name, Int8 value)
1055 {
1056 if (s_LogRequests) {
1057 s_AddParamName(m_Data, name);
1058 s_AddToLog(m_Data, value);
1059 }
1060 return *this;
1061 }
1062
1063 CSrvDiagMsg&
PrintParam(CTempString name,Uint8 value)1064 CSrvDiagMsg::PrintParam(CTempString name, Uint8 value)
1065 {
1066 if (s_LogRequests) {
1067 s_AddParamName(m_Data, name);
1068 s_AddToLog(m_Data, value);
1069 }
1070 return *this;
1071 }
1072
1073 CSrvDiagMsg&
PrintParam(CTempString name,double value)1074 CSrvDiagMsg::PrintParam(CTempString name, double value)
1075 {
1076 if (s_LogRequests) {
1077 s_AddParamName(m_Data, name);
1078 s_AddToLog(m_Data, value);
1079 }
1080 return *this;
1081 }
1082
1083 void
StopRequest(void)1084 CSrvDiagMsg::StopRequest(void)
1085 {
1086 StopRequest(m_Thr->cur_task->m_DiagCtx);
1087 }
1088
1089 void
StopRequest(CRequestContext * ctx)1090 CSrvDiagMsg::StopRequest(CRequestContext* ctx)
1091 {
1092 if (!CDiagContext::IsCtxRunning(ctx)) {
1093 SRV_FATAL("Unexpected StopRequest call");
1094 }
1095
1096 if (s_LogRequests) {
1097 s_AddLogPrefix(m_Thr, m_Data, ctx);
1098 s_AddToLog(m_Data, "request-stop ");
1099 s_AddToLog(m_Data, ctx->GetRequestStatus());
1100 *m_Data->cur_ptr++ = ' ';
1101 CTimeSpan span(ctx->GetRequestTimer().Elapsed());
1102 s_AddToLog(m_Data, span.GetCompleteSeconds());
1103 *m_Data->cur_ptr++ = '.';
1104 s_AddToLog(m_Data, span.GetNanoSecondsAfterSecond(), 9);
1105 *m_Data->cur_ptr++ = ' ';
1106 s_AddToLog(m_Data, ctx->GetBytesRd());
1107 *m_Data->cur_ptr++ = ' ';
1108 s_AddToLog(m_Data, ctx->GetBytesWr());
1109 Flush();
1110 }
1111
1112 CDiagContext::StopCtxRequest(ctx);
1113 }
1114
1115 void
Flush(void)1116 CSrvDiagMsg::Flush(void)
1117 {
1118 s_CheckBufSize(m_Data, 1);
1119 if (m_Data->buf) {
1120 *m_Data->cur_ptr++ = '\n';
1121 }
1122 m_Data->cur_msg_ptr = m_Data->cur_ptr;
1123 if (m_Data->severity == SoftFatal) {
1124 switch (s_SoftFatal) {
1125 default:
1126 case 0: m_Data->severity = Fatal; break;
1127 case 1: CTaskServer::RequestShutdown(eSrvFastShutdown); break;
1128 case 2: break;
1129 }
1130 }
1131 if (m_Data->severity == Fatal) {
1132 s_DoFatalAbort(m_Data);
1133 }
1134 s_CheckBufSize(m_Data, kOneRecReserve);
1135 }
1136
1137 const CSrvDiagMsg&
operator <<(CTempString str) const1138 CSrvDiagMsg::operator<< (CTempString str) const
1139 {
1140 if (s_CheckOldStyleStart(this)) {
1141 if (s_InApplog)
1142 s_AddToLogStripLF(m_Data, str);
1143 else
1144 s_AddToLog(m_Data, str);
1145 }
1146 return *this;
1147 }
1148
1149 const CSrvDiagMsg&
operator <<(Int8 num) const1150 CSrvDiagMsg::operator<< (Int8 num) const
1151 {
1152 if (s_CheckOldStyleStart(this))
1153 s_AddToLog(m_Data, num);
1154 return *this;
1155 }
1156
1157 const CSrvDiagMsg&
operator <<(Uint8 num) const1158 CSrvDiagMsg::operator<< (Uint8 num) const
1159 {
1160 if (s_CheckOldStyleStart(this))
1161 s_AddToLog(m_Data, num);
1162 return *this;
1163 }
1164
1165 const CSrvDiagMsg&
operator <<(double num) const1166 CSrvDiagMsg::operator<< (double num) const
1167 {
1168 if (s_CheckOldStyleStart(this))
1169 s_AddToLog(m_Data, num);
1170 return *this;
1171 }
1172
1173 const CSrvDiagMsg&
operator <<(const void * ptr) const1174 CSrvDiagMsg::operator<< (const void* ptr) const
1175 {
1176 if (s_CheckOldStyleStart(this)) {
1177 NStr::PtrToString(m_Data->tmp_str, ptr);
1178 s_AddToLog(m_Data, m_Data->tmp_str);
1179 }
1180 return *this;
1181 }
1182
1183 const CSrvDiagMsg&
operator <<(const exception & ex) const1184 CSrvDiagMsg::operator<< (const exception& ex) const
1185 {
1186 if (s_CheckOldStyleStart(this)) {
1187 if (s_InApplog)
1188 s_AddToLogStripLF(m_Data, ex.what());
1189 else
1190 s_AddToLog(m_Data, ex.what());
1191 }
1192 return *this;
1193 }
1194
1195
1196 void
SetDiagCtx(CRequestContext * ctx)1197 CSrvTask::SetDiagCtx(CRequestContext* ctx)
1198 {
1199 if (!ctx) {
1200 return;
1201 }
1202 ctx->AddReference();
1203 if (!m_DiagCtx) {
1204 m_DiagCtx = ctx;
1205 if (m_DiagChain)
1206 m_DiagChain[0] = ctx;
1207 return;
1208 }
1209 if (!m_DiagChain) {
1210 m_DiagChain = (CRequestContext**)malloc(sizeof(m_DiagCtx) * 2);
1211 #if __NC_MEMMAN_USE_STD_MALLOC
1212 m_DiagChainSize = sizeof(m_DiagCtx) * 2;
1213 memset(m_DiagChain, 0, m_DiagChainSize);
1214 #else
1215 memset(m_DiagChain, 0, GetMemSize(m_DiagChain));
1216 #endif
1217 m_DiagChain[0] = m_DiagCtx;
1218 m_DiagChain[1] = m_DiagCtx = ctx;
1219 return;
1220 }
1221
1222 #if __NC_MEMMAN_USE_STD_MALLOC
1223 Uint4 mem_cap = Uint4(m_DiagChainSize / sizeof(m_DiagCtx));
1224 #else
1225 Uint4 mem_cap = Uint4(GetMemSize(m_DiagChain) / sizeof(m_DiagCtx));
1226 #endif
1227 Uint4 cnt_in_chain = mem_cap;
1228 while (!m_DiagChain[cnt_in_chain - 1]) {
1229 if (--cnt_in_chain == 0) {
1230 SRV_FATAL("m_DiagChain broken");
1231 }
1232 }
1233 if (cnt_in_chain == mem_cap) {
1234 m_DiagChain = (CRequestContext**)
1235 realloc(m_DiagChain, mem_cap * 2 * sizeof(m_DiagCtx));
1236 #if __NC_MEMMAN_USE_STD_MALLOC
1237 m_DiagChainSize = mem_cap * 2 * sizeof(m_DiagCtx);
1238 memset(&m_DiagChain[mem_cap], 0,
1239 m_DiagChainSize - mem_cap * sizeof(m_DiagCtx));
1240 #else
1241 memset(&m_DiagChain[mem_cap], 0,
1242 GetMemSize(m_DiagChain) - mem_cap * sizeof(m_DiagCtx));
1243 #endif
1244 }
1245 m_DiagChain[cnt_in_chain] = m_DiagCtx = ctx;
1246 }
1247
1248 void
CreateNewDiagCtx(void)1249 CSrvTask::CreateNewDiagCtx(void)
1250 {
1251 CRequestContext* ctx = new CRequestContext();
1252 ctx->SetRequestID();
1253 SetDiagCtx(ctx);
1254 }
1255
1256 void
ReleaseDiagCtx(void)1257 CSrvTask::ReleaseDiagCtx(void)
1258 {
1259 CRequestContext* was_ctx = m_DiagCtx;
1260 m_DiagCtx->RemoveReference();
1261 m_DiagCtx = NULL;
1262 if (!m_DiagChain)
1263 return;
1264
1265 #if __NC_MEMMAN_USE_STD_MALLOC
1266 Uint4 mem_cap = Uint4(m_DiagChainSize / sizeof(m_DiagCtx));
1267 #else
1268 Uint4 mem_cap = Uint4(GetMemSize(m_DiagChain) / sizeof(m_DiagCtx));
1269 #endif
1270 Uint4 cnt_in_chain = mem_cap;
1271 while (!m_DiagChain[cnt_in_chain - 1]) {
1272 if (--cnt_in_chain == 0) {
1273 SRV_FATAL("m_DiagChain broken");
1274 }
1275 }
1276 if (m_DiagChain[--cnt_in_chain] != was_ctx) {
1277 SRV_FATAL("m_DiagChain broken");
1278 }
1279 m_DiagChain[cnt_in_chain] = NULL;
1280 if (cnt_in_chain != 0)
1281 m_DiagCtx = m_DiagChain[cnt_in_chain - 1];
1282 }
1283
CDiagCompileInfo(void)1284 CDiagCompileInfo::CDiagCompileInfo(void)
1285 : m_File(""),
1286 m_Line(0),
1287 m_CurrFunctName(0),
1288 m_Parsed(false),
1289 m_StrFile(0),
1290 m_StrCurrFunctName(0)
1291 {}
1292
CDiagCompileInfo(const char * file,int line,const char * curr_funct)1293 CDiagCompileInfo::CDiagCompileInfo(const char* file,
1294 int line,
1295 const char* curr_funct)
1296 : m_File(file),
1297 m_Line(line),
1298 m_CurrFunctName(curr_funct),
1299 m_Parsed(false),
1300 m_StrFile(0),
1301 m_StrCurrFunctName(0)
1302 {
1303 if (!file) {
1304 m_File = "";
1305 return;
1306 }
1307 }
1308
CDiagCompileInfo(const string & file,int line,const string & curr_funct,const string & module)1309 CDiagCompileInfo::CDiagCompileInfo(const string& file,
1310 int line,
1311 const string& curr_funct,
1312 const string& module)
1313 : m_File(""),
1314 m_Line(line),
1315 m_CurrFunctName(""),
1316 m_Parsed(false),
1317 m_StrFile(0),
1318 m_StrCurrFunctName(0)
1319 {
1320 if ( !file.empty() ) {
1321 m_StrFile = new char[file.size() + 1];
1322 strcpy(m_StrFile, file.c_str());
1323 m_File = m_StrFile;
1324 }
1325 if ( !curr_funct.empty() ) {
1326 m_StrCurrFunctName = new char[curr_funct.size() + 1];
1327 strcpy(m_StrCurrFunctName, curr_funct.c_str());
1328 m_CurrFunctName = m_StrCurrFunctName;
1329 }
1330 }
1331
~CDiagCompileInfo(void)1332 CDiagCompileInfo::~CDiagCompileInfo(void)
1333 {
1334 delete[] m_StrFile;
1335 delete[] m_StrCurrFunctName;
1336 }
1337
1338 void
ParseCurrFunctName(void) const1339 CDiagCompileInfo::ParseCurrFunctName(void) const
1340 {
1341 m_Parsed = true;
1342 CTempString class_name, func_name;
1343 s_ParseFuncName(m_CurrFunctName, class_name, func_name);
1344 m_FunctName.assign(func_name.data(), func_name.size());
1345 m_ClassName.assign(class_name.data(), class_name.size());
1346 }
1347
1348
1349 CNcbiOstream&
Write(CNcbiOstream & os,int flags) const1350 SDiagMessage::Write(CNcbiOstream& os, int flags /* = 0 */) const
1351 {
1352 string sev = s_SevNames[s_ConvertSeverity(severity)];
1353 os << setfill(' ') << setw(13) // add 1 for space
1354 << setiosflags(IOS_BASE::left) << setw(0)
1355 << sev << ':'
1356 << resetiosflags(IOS_BASE::left)
1357 << ' ';
1358
1359 // <module>-<err_code>.<err_subcode> or <module>-<err_text>
1360 if (err_code || err_subcode || err_text) {
1361 if (err_text) {
1362 os << '(' << err_text << ')';
1363 } else {
1364 os << '(' << err_code << '.' << err_subcode << ')';
1365 }
1366 }
1367 os << ' ';
1368
1369 // "<file>"
1370 bool print_file = file && *file;
1371 if ( print_file ) {
1372 const char* x_file;
1373 size_t x_file_len;
1374 ExtractFileName(file, x_file, x_file_len);
1375 os << '"' << string(x_file, x_file_len) << '"';
1376 }
1377 else {
1378 os << "\"UNK_FILE\"";
1379 }
1380 // , line <line>
1381 os << ", line " << line;
1382 os << ": ";
1383
1384 // Class::Function
1385 bool print_loc = (nclass && *nclass ) || (func && *func);
1386 if (print_loc) {
1387 // Class:: Class::Function() ::Function()
1388 if (nclass && *nclass) {
1389 os << nclass;
1390 }
1391 os << "::";
1392 if (func && *func) {
1393 os << func << "() ";
1394 }
1395 }
1396 else {
1397 os << "UNK_FUNC ";
1398 }
1399
1400 os << "--- ";
1401
1402 // [<prefix1>::<prefix2>::.....]
1403 if (prefix && *prefix)
1404 os << '[' << prefix << "] ";
1405
1406 // <message>
1407 if (len)
1408 os.write(buf, len);
1409
1410 // Endl
1411 if ((flags & fNoEndl) == 0)
1412 os << NcbiEndl;
1413
1414 return os;
1415 }
1416
1417
CLogWriter(void)1418 CLogWriter::CLogWriter(void)
1419 {
1420 #if __NC_TASKS_MONITOR
1421 m_TaskName = "CLogWriter";
1422 #endif
1423 }
1424
~CLogWriter(void)1425 CLogWriter::~CLogWriter(void)
1426 {}
1427
1428 void
ExecuteSlice(TSrvThreadNum)1429 CLogWriter::ExecuteSlice(TSrvThreadNum /* thr_num */)
1430 {
1431 // those who add data into queue, make this runnable
1432
1433 s_CheckFatalAbort();
1434 // if log file was open for too long, close it
1435 // so that app_log could move it
1436 if (CSrvTime::CurSecs() - s_LastReopenTime >= s_FileReopenPeriod && s_LogFd != -1)
1437 {
1438 #ifdef NCBI_OS_LINUX
1439 close(s_LogFd);
1440 #endif
1441 s_LogFd = -1;
1442 }
1443
1444 // get from the queue, write into log
1445 s_WriteQueueLock.Lock();
1446 if (s_WriteQueue.empty()) {
1447 s_WriteQueueLock.Unlock();
1448 return;
1449 }
1450 CTempString str = s_WriteQueue.front();
1451 s_WriteQueue.pop_front();
1452 bool have_more = !s_WriteQueue.empty();
1453 s_WriteQueueLock.Unlock();
1454
1455 s_WriteLog(str.data(), str.size());
1456 free((void*)str.data());
1457
1458 if (have_more)
1459 SetRunnable();
1460 }
1461
1462 END_NCBI_SCOPE;
1463