• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taosdata / TDengine / #4933

20 Jan 2026 10:44AM UTC coverage: 66.671% (+0.03%) from 66.646%
#4933

push

travis-ci

web-flow
merge: from main to 3.0 #34340

73 of 178 new or added lines in 9 files covered. (41.01%)

1199 existing lines in 124 files now uncovered.

203121 of 304663 relevant lines covered (66.67%)

132228377.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

61.11
/source/util/src/tlog.c
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15

16
#define _DEFAULT_SOURCE
17
#include "tlog.h"
18
#include "os.h"
19
#include "tconfig.h"
20
#include "tglobal.h"
21
#include "tjson.h"
22
#include "ttime.h"
23
#include "tutil.h"
24
#include "tcommon.h"
25

26
#define LOG_MAX_LINE_SIZE              (10024)
27
#define LOG_MAX_LINE_BUFFER_SIZE       (LOG_MAX_LINE_SIZE + 3)
28
#define LOG_MAX_STACK_LINE_SIZE        (512)
29
#define LOG_MAX_STACK_LINE_BUFFER_SIZE (LOG_MAX_STACK_LINE_SIZE + 3)
30
#define LOG_MAX_LINE_DUMP_SIZE         (1024 * 1024)
31
#define LOG_MAX_LINE_DUMP_BUFFER_SIZE  (LOG_MAX_LINE_DUMP_SIZE + 128)
32

33
#define LOG_FILE_DAY_LEN 64
34

35
#define LOG_DEFAULT_BUF_SIZE (20 * 1024 * 1024)  // 20MB
36
#define LOG_SLOW_BUF_SIZE    (10 * 1024 * 1024)  // 10MB
37

38
#define LOG_DEFAULT_INTERVAL 25
39
#define LOG_INTERVAL_STEP    5
40
#define LOG_MIN_INTERVAL     5
41
#define LOG_MAX_INTERVAL     25
42
#define LOG_MAX_WAIT_MSEC    1000
43

44
#define LOG_BUF_BUFFER(x) ((x)->buffer)
45
#define LOG_BUF_START(x)  ((x)->buffStart)
46
#define LOG_BUF_END(x)    ((x)->buffEnd)
47
#define LOG_BUF_SIZE(x)   ((x)->buffSize)
48
#define LOG_BUF_MUTEX(x)  ((x)->buffMutex)
49

50
#ifdef TD_ENTERPRISE
51
#define LOG_EDITION_FLG ("E")
52
#else
53
#define LOG_EDITION_FLG ("C")
54
#endif
55

56
typedef enum {
57
  LOG_OUTPUT_FILE = 0,    // default
58
  LOG_OUTPUT_STDOUT = 1,  // stdout set by -o option on the command line
59
  LOG_OUTPUT_STDERR = 2,  // stderr set by -o option on the command line
60
  LOG_OUTPUT_NULL = 4,    // /dev/null set by -o option on the command line
61
} ELogOutputType;
62

63
typedef struct {
64
  char         *buffer;
65
  int32_t       buffStart;
66
  int32_t       buffEnd;
67
  int32_t       buffSize;
68
  int32_t       minBuffSize;
69
  TdFilePtr     pFile;
70
  int32_t       stop;
71
  TdThread      asyncThread;
72
  TdThreadMutex buffMutex;
73
  int32_t       writeInterval;
74
  int32_t       lastDuration;
75
  int32_t       lock;
76
} SLogBuff;
77

78
typedef struct {
79
  int32_t       fileNum;
80
  int32_t       lines;
81
  int32_t       flag;
82
  int32_t       openInProgress;
83
  int64_t       lastKeepFileSec;
84
  int64_t       timestampToday;
85
  int8_t        outputType;  // ELogOutputType
86
  pid_t         pid;
87
  char          logName[PATH_MAX];
88
  char          slowLogName[PATH_MAX];
89
  SLogBuff     *logHandle;
90
  SLogBuff     *slowHandle;
91
  TdThreadMutex logMutex;
92
} SLogObj;
93

94
extern SConfig *tsCfg;
95
static int8_t   tsLogInited = 0;
96
static SLogObj  tsLogObj = {.fileNum = 1, .slowHandle = NULL};
97
static int64_t  tsAsyncLogLostLines = 0;
98
static int32_t  tsDaylightActive; /* Currently in daylight saving time. */
99
static SRWLatch tsLogRotateLatch = 0;
100

101
bool tsLogEmbedded = 0;
102
bool tsAsyncLog = true;
103
#ifdef ASSERT_NOT_CORE
104
bool tsAssert = false;
105
#else
106
bool tsAssert = true;
107
#endif
108
int32_t tsNumOfLogLines = 10000000;
109
int32_t tsLogKeepDays = 0;
110
char   *tsLogOutput = NULL;
111
LogFp   tsLogFp = NULL;
112
int64_t tsNumOfErrorLogs = 0;
113
int64_t tsNumOfInfoLogs = 0;
114
int64_t tsNumOfDebugLogs = 0;
115
int64_t tsNumOfTraceLogs = 0;
116
int64_t tsNumOfSlowLogs = 0;
117

118
// log
119
int32_t dDebugFlag = 131;
120
int32_t vDebugFlag = 131;
121
int32_t mDebugFlag = 131;
122
int32_t cDebugFlag = 131;
123
int32_t jniDebugFlag = 131;
124
int32_t tmrDebugFlag = 131;
125
int32_t uDebugFlag = 131;
126
int32_t rpcDebugFlag = 131;
127
int32_t qDebugFlag = 131;
128
int32_t stDebugFlag = 131;
129
int32_t wDebugFlag = 131;
130
int32_t azDebugFlag = 131;
131
int32_t tssDebugFlag = 131;
132
int32_t sDebugFlag = 131;
133
int32_t tsdbDebugFlag = 131;
134
int32_t tdbDebugFlag = 131;
135
int32_t tqDebugFlag = 131;
136
int32_t fsDebugFlag = 131;
137
int32_t metaDebugFlag = 131;
138
int32_t udfDebugFlag = 131;
139
int32_t smaDebugFlag = 131;
140
int32_t idxDebugFlag = 131;
141
int32_t sndDebugFlag = 131;
142
int32_t bndDebugFlag = 131;
143
int32_t xndDebugFlag = 131;
144
int32_t simDebugFlag = 131;
145
int32_t bseDebugFlag = 131;
146

147
int32_t tqClientDebugFlag = 131;
148

149
int64_t dbgEmptyW = 0;
150
int64_t dbgWN = 0;
151
int64_t dbgSmallWN = 0;
152
int64_t dbgBigWN = 0;
153
int64_t dbgWSize = 0;
154

155
static void     *taosAsyncOutputLog(void *param);
156
static int32_t   taosPushLogBuffer(SLogBuff *pLogBuf, const char *msg, int32_t msgLen);
157
static SLogBuff *taosLogBuffNew(int32_t bufSize);
158
static void      taosCloseLogByFd(TdFilePtr pFile);
159
static int32_t   taosInitNormalLog(const char *fn, int32_t maxFileNum);
160
static void      taosWriteLog(SLogBuff *pLogBuf);
161
static void      taosWriteSlowLog(SLogBuff *pLogBuf);
162

163
static int32_t taosStartLog() {
2,385,670✔
164
  TdThreadAttr threadAttr;
2,373,344✔
165
  (void)taosThreadAttrInit(&threadAttr);
2,385,670✔
166
#ifdef TD_COMPACT_OS
167
  (void)taosThreadAttrSetStackSize(&threadAttr, STACK_SIZE_SMALL);
168
#endif
169
  if (taosThreadCreate(&(tsLogObj.logHandle->asyncThread), &threadAttr, taosAsyncOutputLog, tsLogObj.logHandle) != 0) {
2,385,670✔
170
    return terrno;
×
171
  }
172
  (void)taosThreadAttrDestroy(&threadAttr);
2,385,670✔
173
  return 0;
2,385,670✔
174
}
175

176
static int32_t getDay(char *buf, int32_t bufSize) {
2,384,863✔
177
  time_t  t;
2,372,537✔
178
  int32_t code = taosTime(&t);
2,384,863✔
179
  if (code != 0) {
2,384,863✔
180
    return code;
×
181
  }
182
  struct tm tmInfo;
2,372,537✔
183
  if (taosLocalTime(&t, &tmInfo, buf, bufSize, NULL) != NULL) {
2,384,863✔
184
    TAOS_UNUSED(taosStrfTime(buf, bufSize, "%Y-%m-%d", &tmInfo));
2,384,863✔
185
  }
186
  return 0;
2,384,863✔
187
}
188

189
static void getFullPathName(char *fullName, const char *logName) {
4,770,533✔
190
  if (strlen(tsLogDir) != 0) {
4,770,533✔
191
    char lastC = tsLogDir[strlen(tsLogDir) - 1];
4,769,726✔
192
    if (lastC == '\\' || lastC == '/') {
4,769,726✔
193
      snprintf(fullName, PATH_MAX,
1,528,774✔
194
               "%s"
195
               "%s",
196
               tsLogDir, logName);
197
    } else {
198
      snprintf(fullName, PATH_MAX, "%s" TD_DIRSEP "%s", tsLogDir, logName);
3,240,952✔
199
    }
200
  } else {
201
    snprintf(fullName, PATH_MAX, "%s", logName);
807✔
202
  }
203
}
4,770,533✔
204

205
int32_t taosInitSlowLog() {
2,384,863✔
206
  char logFileName[64] = {0};
2,384,863✔
207
#ifdef CUS_PROMPT
208
  (void)snprintf(logFileName, 64, "%sSlowLog", CUS_PROMPT);
2,384,863✔
209
#else
210
  (void)snprintf(logFileName, 64, "taosSlowLog");
211
#endif
212

213
  getFullPathName(tsLogObj.slowLogName, logFileName);
2,384,863✔
214

215
  char    name[PATH_MAX + TD_TIME_STR_LEN] = {0};
2,384,863✔
216
  char    day[TD_TIME_STR_LEN] = {0};
2,384,863✔
217
  int32_t code = getDay(day, sizeof(day));
2,384,863✔
218
  if (code != 0) {
2,384,863✔
219
    (void)printf("failed to get day, reason:%s\n", tstrerror(code));
×
220
    SET_ERROR_MSG("failed to get day, reason:%s", tstrerror(code));
×
221
    return code;
×
222
  }
223
  (void)snprintf(name, PATH_MAX + TD_TIME_STR_LEN, "%s.%s", tsLogObj.slowLogName, day);
2,384,863✔
224

225
  tsLogObj.timestampToday = taosGetTimestampToday(TSDB_TIME_PRECISION_SECONDS, NULL);
2,384,863✔
226
  tsLogObj.slowHandle = taosLogBuffNew(LOG_SLOW_BUF_SIZE);
2,384,863✔
227
  if (tsLogObj.slowHandle == NULL) return terrno;
2,384,863✔
228

229
  TAOS_UNUSED(taosUmaskFile(0));
2,384,863✔
230
  tsLogObj.slowHandle->pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_READ | TD_FILE_WRITE | TD_FILE_APPEND);
2,384,863✔
231
  if (tsLogObj.slowHandle->pFile == NULL) {
2,384,863✔
232
    (void)printf("\nfailed to open slow log file:%s, reason:%s\n", name, strerror(ERRNO));
×
233
    SET_ERROR_MSG("failed to open slow log file:%s, reason:%s", name, strerror(ERRNO));
×
234
    return terrno;
×
235
  }
236

237
  return 0;
2,384,863✔
238
}
239

240
int32_t taosInitLogOutput(const char **ppLogName) {
2,387,399✔
241
  const char *pLog = tsLogOutput;
2,387,399✔
242
  const char *pLogName = NULL;
2,387,399✔
243
  if (pLog) {
2,387,399✔
244
    if (!tIsValidFilePath(pLog, NULL)) {
190✔
245
      fprintf(stderr, "invalid log output destination:%s, contains illegal char\n", pLog);
15✔
246
      return TSDB_CODE_INVALID_CFG;
15✔
247
    }
248
    if (0 == strcasecmp(pLog, "stdout")) {
175✔
UNCOV
249
      tsLogObj.outputType = LOG_OUTPUT_STDOUT;
×
UNCOV
250
      if (ppLogName) *ppLogName = pLog;
×
UNCOV
251
      return 0;
×
252
    }
253
    if (0 == strcasecmp(pLog, "stderr")) {
175✔
UNCOV
254
      tsLogObj.outputType = LOG_OUTPUT_STDERR;
×
UNCOV
255
      if (ppLogName) *ppLogName = pLog;
×
UNCOV
256
      return 0;
×
257
    }
258
    if (0 == strcasecmp(pLog, "/dev/null")) {
175✔
259
      tsLogObj.outputType = LOG_OUTPUT_NULL;
×
260
      if (ppLogName) *ppLogName = pLog;
×
261
      return 0;
×
262
    }
263
    int32_t len = strlen(pLog);
175✔
264
    if (len < 1) {
175✔
265
      fprintf(stderr, "invalid log output destination:%s, should not be empty\n", pLog);
×
266
      return TSDB_CODE_INVALID_CFG;
×
267
    }
268
    const char *p = pLog + (len - 1);
175✔
269
    if (*p == '/' || *p == '\\') {
175✔
270
      return 0;
115✔
271
    }
272

273
    if ((p = strrchr(pLog, '/')) || (p = strrchr(pLog, '\\'))) {
60✔
274
      pLogName = p + 1;
30✔
275
    } else {
276
      pLogName = pLog;
30✔
277
    }
278
    if (strcmp(pLogName, ".") == 0 || strcmp(pLogName, "..") == 0) {
60✔
279
      fprintf(stderr, "invalid log output destination:%s\n", pLog);
×
280
      return TSDB_CODE_INVALID_CFG;
×
281
    }
282

283
    if (!tIsValidFileName(pLogName, NULL)) {
60✔
284
      fprintf(stderr, "invalid log output destination:%s, contains illegal char\n", pLog);
×
285
      return TSDB_CODE_INVALID_CFG;
×
286
    }
287
    if (ppLogName) *ppLogName = pLogName;
60✔
288
  }
289
  return 0;
2,387,269✔
290
}
291

292
int32_t taosInitLog(const char *logName, int32_t maxFiles, bool tsc) {
2,385,670✔
293
  if (atomic_val_compare_exchange_8(&tsLogInited, 0, 1) != 0) return 0;
2,385,670✔
294
  int32_t code = osUpdate();
2,385,670✔
295
  if (code != 0) {
2,385,670✔
296
    uError("failed to update os info, reason:%s", tstrerror(code));
×
297
  }
298

299
  if (tsLogObj.outputType == LOG_OUTPUT_STDOUT || tsLogObj.outputType == LOG_OUTPUT_STDERR ||
2,385,670✔
300
      tsLogObj.outputType == LOG_OUTPUT_NULL) {
2,385,670✔
UNCOV
301
    return 0;
×
302
  }
303

304
  TAOS_CHECK_RETURN(taosInitNormalLog(logName, maxFiles));
2,385,670✔
305
  if (tsc) {
2,385,670✔
306
    TAOS_CHECK_RETURN(taosInitSlowLog());
2,384,863✔
307
  }
308
  TAOS_CHECK_RETURN(taosStartLog());
2,385,670✔
309
  return 0;
2,385,670✔
310
}
311

312
void taosSetNoNewFile() { tsLogObj.openInProgress = 1; }
×
313

314
static void taosStopLog() {
2,388,107✔
315
  if (tsLogObj.logHandle) {
2,388,107✔
316
    tsLogObj.logHandle->stop = 1;
2,385,612✔
317
  }
318
  if (tsLogObj.slowHandle) {
2,388,107✔
319
    tsLogObj.slowHandle->stop = 1;
2,384,805✔
320
  }
321
}
2,388,107✔
322

323
void taosCloseLog() {
2,388,107✔
324
  taosStopLog();
2,388,107✔
325

326
  if (tsLogObj.logHandle != NULL && taosCheckPthreadValid(tsLogObj.logHandle->asyncThread)) {
2,388,107✔
327
    (void)taosThreadJoin(tsLogObj.logHandle->asyncThread, NULL);
2,385,612✔
328
    taosThreadClear(&tsLogObj.logHandle->asyncThread);
2,385,612✔
329
  }
330

331
  if (tsLogObj.slowHandle != NULL) {
2,388,107✔
332
    (void)taosThreadMutexDestroy(&tsLogObj.slowHandle->buffMutex);
2,384,805✔
333
    (void)taosCloseFile(&tsLogObj.slowHandle->pFile);
2,384,805✔
334
    taosMemoryFreeClear(tsLogObj.slowHandle->buffer);
2,384,805✔
335
    taosMemoryFreeClear(tsLogObj.slowHandle);
2,384,805✔
336
  }
337

338
  if (tsLogObj.logHandle != NULL) {
2,388,107✔
339
    tsLogInited = 0;
2,385,612✔
340

341
    (void)taosThreadMutexDestroy(&tsLogObj.logHandle->buffMutex);
2,385,612✔
342
    (void)taosCloseFile(&tsLogObj.logHandle->pFile);
2,385,612✔
343
    taosMemoryFreeClear(tsLogObj.logHandle->buffer);
2,385,612✔
344
    (void)taosThreadMutexDestroy(&tsLogObj.logMutex);
2,385,612✔
345
    taosMemoryFreeClear(tsLogObj.logHandle);
2,385,612✔
346
    tsLogObj.logHandle = NULL;
2,385,612✔
347
  }
348
  taosMemoryFreeClear(tsLogOutput);
2,388,107✔
349
}
2,388,107✔
350

351
static bool taosLockLogFile(TdFilePtr pFile) {
3,924,666✔
352
  if (pFile == NULL) return false;
3,924,666✔
353

354
  if (tsLogObj.fileNum > 1) {
3,924,666✔
355
    int32_t ret = taosLockFile(pFile);
2,771,654✔
356
    if (ret == 0) {
2,771,654✔
357
      return true;
2,086,576✔
358
    }
359
  }
360

361
  return false;
1,838,090✔
362
}
363

364
static void taosUnLockLogFile(TdFilePtr pFile) {
857,996✔
365
  if (pFile == NULL) return;
857,996✔
366

367
  if (tsLogObj.fileNum > 1) {
857,996✔
368
    int32_t code = taosUnLockFile(pFile);
857,947✔
369
    if (code != 0) {
857,947✔
370
      TAOS_UNUSED(printf("failed to unlock log file:%p, reason:%s\n", pFile, tstrerror(code)));
×
371
    }
372
  }
373
}
374

375
static void taosReserveOldLog(char *oldName, char *keepName) {
336✔
376
  if (tsLogKeepDays == 0) {
336✔
377
    keepName[0] = 0;
336✔
378
    return;
336✔
379
  }
380

381
  int32_t code = 0;
×
382
  int64_t fileSec = taosGetTimestampSec();
×
383
  if (tsLogObj.lastKeepFileSec < fileSec) {
×
384
    tsLogObj.lastKeepFileSec = fileSec;
×
385
  } else {
386
    fileSec = ++tsLogObj.lastKeepFileSec;
×
387
  }
388
  snprintf(keepName, PATH_MAX + 20, "%s.%" PRId64, tsLogObj.logName, fileSec);
×
389
  if ((code = taosRenameFile(oldName, keepName))) {
×
390
    keepName[0] = 0;
×
391
    uError("failed to rename file:%s to %s since %s", oldName, keepName, tstrerror(code));
×
392
  }
393
}
394

395
static void taosKeepOldLog(char *oldName) {
98✔
396
  if (oldName[0] != 0) {
98✔
397
    int32_t   code = 0, lino = 0;
×
398
    TdFilePtr oldFile = NULL;
×
399
    if ((oldFile = taosOpenFile(oldName, TD_FILE_READ))) {
×
400
      TAOS_CHECK_GOTO(taosLockFile(oldFile), &lino, _exit2);
×
401
      char compressFileName[PATH_MAX + 20];
×
402
      snprintf(compressFileName, PATH_MAX + 20, "%s.gz", oldName);
×
403
      TAOS_CHECK_GOTO(taosCompressFile(oldName, compressFileName), &lino, _exit1);
×
404
      TAOS_CHECK_GOTO(taosRemoveFile(oldName), &lino, _exit1);
×
405
    _exit1:
×
406
      TAOS_UNUSED(taosUnLockFile(oldFile));
×
407
    _exit2:
×
408
      TAOS_UNUSED(taosCloseFile(&oldFile));
×
409
    } else {
410
      code = terrno;
×
411
    }
412
    if (code != 0 && tsLogEmbedded == 1) {  // print error messages only in embedded log mode
×
413
      // avoid using uWarn or uError, as they may open a new log file and potentially cause a deadlock.
414
      fprintf(stderr, "WARN: failed at line %d to keep old log file:%s, reason:%s\n", lino, oldName, tstrerror(code));
×
415
    }
416
  }
417
}
98✔
418
typedef struct {
419
  TdFilePtr pOldFile;
420
  char      keepName[PATH_MAX + 20];
421
} OldFileKeeper;
422
static OldFileKeeper *taosOpenNewFile() {
336✔
423
  char keepName[PATH_MAX + 20];
336✔
424
  TAOS_UNUSED(snprintf(keepName, sizeof(keepName), "%s.%d", tsLogObj.logName, tsLogObj.flag));
336✔
425

426
  tsLogObj.flag ^= 1;
336✔
427
  tsLogObj.lines = 0;
336✔
428
  char name[PATH_MAX + 20];
336✔
429
  TAOS_UNUSED(snprintf(name, sizeof(name), "%s.%d", tsLogObj.logName, tsLogObj.flag));
336✔
430

431
  TAOS_UNUSED(taosUmaskFile(0));
336✔
432

433
  TdFilePtr pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC);
336✔
434
  if (pFile == NULL) {
336✔
435
    tsLogObj.flag ^= 1;
×
436
    tsLogObj.lines = tsNumOfLogLines - 1000;
×
437
    uError("open new log file %s fail! reason:%s, reuse lastlog", name, tstrerror(terrno));
×
438
    return NULL;
×
439
  }
440

441
  TAOS_UNUSED(taosLockLogFile(pFile));
336✔
442
  if (taosLSeekFile(pFile, 0, SEEK_SET) < 0) {
336✔
443
    uWarn("failed to seek file:%s, reason:%s", name, tstrerror(terrno));
×
444
  }
445

446
  TdFilePtr pOldFile = tsLogObj.logHandle->pFile;
336✔
447
  tsLogObj.logHandle->pFile = pFile;
336✔
448
  tsLogObj.lines = 0;
336✔
449
  OldFileKeeper *oldFileKeeper = taosMemoryMalloc(sizeof(OldFileKeeper));
336✔
450
  if (oldFileKeeper == NULL) {
336✔
451
    uError("create old log keep info faild! mem is not enough.");
×
452
    return NULL;
×
453
  }
454
  oldFileKeeper->pOldFile = pOldFile;
336✔
455
  taosReserveOldLog(keepName, oldFileKeeper->keepName);
336✔
456

457
  uInfo("   new log file:%d is opened", tsLogObj.flag);
336✔
458
  uInfo("==================================");
336✔
459
  return oldFileKeeper;
336✔
460
}
461

462
static void *taosThreadToCloseOldFile(void *param) {
336✔
463
  if (!param) return NULL;
336✔
464
  OldFileKeeper *oldFileKeeper = (OldFileKeeper *)param;
336✔
465
  taosSsleep(20);
336✔
466
  taosWLockLatch(&tsLogRotateLatch);
98✔
467
  taosCloseLogByFd(oldFileKeeper->pOldFile);
98✔
468
  taosKeepOldLog(oldFileKeeper->keepName);
98✔
469
  taosMemoryFree(oldFileKeeper);
98✔
470
  if (tsLogKeepDays != 0) {
98✔
471
    taosRemoveOldFiles(tsLogDir, abs(tsLogKeepDays));
49✔
472
  }
473
  taosWUnLockLatch(&tsLogRotateLatch);
98✔
474
  return NULL;
98✔
475
}
476

477
static int32_t taosOpenNewLogFile() {
336✔
478
  (void)taosThreadMutexLock(&tsLogObj.logMutex);
336✔
479

480
  if (tsLogObj.lines > tsNumOfLogLines && tsLogObj.openInProgress == 0) {
336✔
481
    tsLogObj.openInProgress = 1;
336✔
482

483
    uInfo("open new log file ......");
336✔
484
    TdThread     thread;
336✔
485
    TdThreadAttr attr;
336✔
486
    (void)taosThreadAttrInit(&attr);
336✔
487
    (void)taosThreadAttrSetDetachState(&attr, PTHREAD_CREATE_DETACHED);
336✔
488
#ifdef TD_COMPACT_OS
489
    (void)taosThreadAttrSetStackSize(&attr, STACK_SIZE_SMALL);
490
#endif
491
    OldFileKeeper *oldFileKeeper = taosOpenNewFile();
336✔
492
    if (!oldFileKeeper) {
336✔
493
      tsLogObj.openInProgress = 0;
×
494
      TAOS_UNUSED(taosThreadMutexUnlock(&tsLogObj.logMutex));
×
495
      (void)taosThreadAttrDestroy(&attr);
×
496
      return terrno;
×
497
    }
498
    if (taosThreadCreate(&thread, &attr, taosThreadToCloseOldFile, oldFileKeeper) != 0) {
336✔
499
      uError("failed to create thread to close old log file");
×
500
      taosMemoryFreeClear(oldFileKeeper);
×
501
    }
502
    (void)taosThreadAttrDestroy(&attr);
336✔
503
    tsLogObj.openInProgress = 0;
336✔
504
  }
505

506
  (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
336✔
507

508
  return 0;
336✔
509
}
510

511
void taosOpenNewSlowLogFile() {
×
512
  (void)taosThreadMutexLock(&tsLogObj.logMutex);
×
513
  int64_t delta = taosGetTimestampSec() - tsLogObj.timestampToday;
×
514
  if (delta >= 0 && delta < 86400) {
×
515
    uInfo("timestampToday is already equal to today, no need to open new slow log file");
×
516
    (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
×
517
    return;
×
518
  }
519

520
  for (int32_t i = 1; atomic_val_compare_exchange_32(&tsLogObj.slowHandle->lock, 0, 1) == 1; ++i) {
×
521
    if (i % 1000 == 0) {
×
522
      TAOS_UNUSED(sched_yield());
×
523
    }
524
  }
525
  tsLogObj.slowHandle->lastDuration = LOG_MAX_WAIT_MSEC;  // force write
×
526
  taosWriteLog(tsLogObj.slowHandle);
×
527
  atomic_store_32(&tsLogObj.slowHandle->lock, 0);
×
528

529
  char    day[TD_TIME_STR_LEN] = {0};
×
530
  int32_t code = getDay(day, sizeof(day));
×
531
  if (code != 0) {
×
532
    uError("failed to get day, reason:%s", tstrerror(code));
×
533
    (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
×
534
    return;
×
535
  }
536
  TdFilePtr pFile = NULL;
×
537
  char      name[PATH_MAX + TD_TIME_STR_LEN] = {0};
×
538
  (void)snprintf(name, PATH_MAX + TD_TIME_STR_LEN, "%s.%s", tsLogObj.slowLogName, day);
×
539
  pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_APPEND);
×
540
  if (pFile == NULL) {
×
541
    uError("open new log file fail! reason:%s, reuse lastlog", strerror(ERRNO));
×
542
    (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
×
543
    return;
×
544
  }
545

546
  TdFilePtr pOldFile = tsLogObj.slowHandle->pFile;
×
547
  tsLogObj.slowHandle->pFile = pFile;
×
548
  (void)taosCloseFile(&pOldFile);
×
549
  tsLogObj.timestampToday = taosGetTimestampToday(TSDB_TIME_PRECISION_SECONDS, NULL);
×
550
  (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
×
551
}
552

553
void taosResetLog() {
238✔
554
  // force create a new log file
555
  tsLogObj.lines = tsNumOfLogLines + 10;
238✔
556

557
  if (tsLogObj.logHandle) {
238✔
558
    int32_t code = taosOpenNewLogFile();
238✔
559
    if (code != 0) {
238✔
560
      uError("failed to open new log file, reason:%s", tstrerror(code));
×
561
    }
562
    uInfo("==================================");
238✔
563
    uInfo("   reset log file ");
238✔
564
  }
565
}
238✔
566

567
void taosLogObjSetToday(int64_t ts) { tsLogObj.timestampToday = ts; }
×
568

569
static bool taosCheckFileIsOpen(char *logFileName) {
3,827,330✔
570
  TdFilePtr pFile = taosOpenFile(logFileName, TD_FILE_WRITE);
3,827,330✔
571
  if (pFile == NULL) {
3,827,330✔
572
    if (lastErrorIsFileNotExist()) {
2,288,670✔
573
      return false;
2,288,670✔
574
    } else {
575
      printf("\n%s:%d failed to open log file:%s, reason:%s\n", __func__, __LINE__, logFileName, strerror(ERRNO));
×
576
      SET_ERROR_MSG("%s:%d failed to open log file:%s, reason:%s", __func__, __LINE__, logFileName, strerror(ERRNO));
×
577
      return true;
×
578
    }
579
  }
580

581
  if (taosLockLogFile(pFile)) {
1,538,660✔
582
    taosUnLockLogFile(pFile);
857,898✔
583
    (void)taosCloseFile(&pFile);
857,898✔
584
    return false;
857,898✔
585
  } else {
586
    (void)taosCloseFile(&pFile);
680,762✔
587
    return true;
680,762✔
588
  }
589
}
590

591
static void decideLogFileName(const char *fn, int32_t maxFileNum) {
2,385,670✔
592
  tsLogObj.fileNum = maxFileNum;
2,385,670✔
593
  if (tsLogObj.fileNum > 1) {
2,385,670✔
594
    for (int32_t i = 0; i < tsLogObj.fileNum; i++) {
1,913,665✔
595
      char fileName[PATH_MAX + 10];
1,897,757✔
596

597
      (void)snprintf(fileName, PATH_MAX + 10, "%s%d.0", fn, i);
1,913,665✔
598
      bool file1open = taosCheckFileIsOpen(fileName);
1,913,665✔
599

600
      (void)snprintf(fileName, PATH_MAX + 10, "%s%d.1", fn, i);
1,913,665✔
601
      bool file2open = taosCheckFileIsOpen(fileName);
1,913,665✔
602

603
      if (!file1open && !file2open) {
1,913,665✔
604
        (void)snprintf(tsLogObj.logName, PATH_MAX, "%s%d", fn, i);
1,232,903✔
605
        return;
1,232,903✔
606
      }
607
    }
608
  }
609

610
  if (strlen(fn) < PATH_MAX) {
1,152,767✔
611
    tstrncpy(tsLogObj.logName, fn, PATH_MAX);
1,152,767✔
612
  }
613
}
614

615
static void decideLogFileNameFlag() {
2,385,670✔
616
  char    name[PATH_MAX] = "\0";
2,385,670✔
617
  int64_t logstat0_mtime = 0;
2,385,670✔
618
  int64_t logstat1_mtime = 0;
2,385,670✔
619
  bool    log0Exist = false;
2,385,670✔
620
  bool    log1Exist = false;
2,385,670✔
621

622
  int32_t logNameLen = strlen(tsLogObj.logName) + 2;
2,385,670✔
623
  if (logNameLen < PATH_MAX) {
2,385,670✔
624
    TAOS_UNUSED(snprintf(name, PATH_MAX, "%s%s", tsLogObj.logName, ".0"));
2,385,670✔
625
    log0Exist = taosStatFile(name, NULL, &logstat0_mtime, NULL) == 0;
2,385,670✔
626
    name[logNameLen - 1] = '1';
2,385,670✔
627
    log1Exist = taosStatFile(name, NULL, &logstat1_mtime, NULL) == 0;
2,385,670✔
628
  }
629

630
  // if none of the log files exist, open 0, if both exists, open the old one
631
  if (!log0Exist && !log1Exist) {
2,385,670✔
632
    tsLogObj.flag = 0;
1,272,415✔
633
  } else if (!log1Exist) {
1,113,255✔
634
    tsLogObj.flag = 0;
1,112,719✔
635
  } else if (!log0Exist) {
536✔
636
    tsLogObj.flag = 1;
×
637
  } else {
638
    tsLogObj.flag = (logstat0_mtime > logstat1_mtime) ? 0 : 1;
536✔
639
  }
640
}
2,385,670✔
641

642
static void processLogFileName(const char *logName, int32_t maxFileNum) {
2,385,670✔
643
  char fullName[PATH_MAX] = {0};
2,385,670✔
644
  getFullPathName(fullName, logName);
2,385,670✔
645
  decideLogFileName(fullName, maxFileNum);
2,385,670✔
646
  decideLogFileNameFlag();
2,385,670✔
647
}
2,385,670✔
648

649
static int32_t taosInitNormalLog(const char *logName, int32_t maxFileNum) {
2,385,670✔
650
  int32_t code = 0, lino = 0;
2,385,670✔
651
#ifdef WINDOWS_STASH
652
  /*
653
   * always set maxFileNum to 1
654
   * means client log filename is unique in windows
655
   */
656
  maxFileNum = 1;
657
#endif
658

659
  processLogFileName(logName, maxFileNum);
2,385,670✔
660

661
  int32_t logNameLen = strlen(tsLogObj.logName) + 2;  // logName + ".0" or ".1"
2,385,670✔
662

663
  if (logNameLen < 0 || logNameLen >= PATH_MAX) {
2,385,670✔
664
    uError("log name:%s is invalid since length:%d is out of range", logName, logNameLen);
×
665
    return TSDB_CODE_INVALID_CFG;
×
666
  }
667

668
  char name[PATH_MAX] = "\0";
2,385,670✔
669
  (void)snprintf(name, sizeof(name), "%s.%d", tsLogObj.logName, tsLogObj.flag);
2,385,670✔
670
  (void)taosThreadMutexInit(&tsLogObj.logMutex, NULL);
2,385,670✔
671

672
  TAOS_UNUSED(taosUmaskFile(0));
2,385,670✔
673
  tsLogObj.logHandle = taosLogBuffNew(LOG_DEFAULT_BUF_SIZE);
2,385,670✔
674
  if (tsLogObj.logHandle == NULL) return terrno;
2,385,670✔
675

676
  tsLogObj.logHandle->pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_READ | TD_FILE_WRITE);
2,385,670✔
677
  if (tsLogObj.logHandle->pFile == NULL) {
2,385,670✔
678
    (void)printf("\n%s:%d failed to open log file:%s, reason:%s\n", __func__, __LINE__, name, strerror(ERRNO));
×
679
    SET_ERROR_MSG("%s:%d failed to open log file:%s, reason:%s", __func__, __LINE__, name, strerror(ERRNO));
×
680
    return terrno;
×
681
  }
682
  TAOS_UNUSED(taosLockLogFile(tsLogObj.logHandle->pFile));
2,385,670✔
683

684
  // only an estimate for number of lines
685
  int64_t filesize = 0;
2,385,670✔
686
  TAOS_CHECK_EXIT(taosFStatFile(tsLogObj.logHandle->pFile, &filesize, NULL));
2,385,670✔
687

688
  tsLogObj.lines = (int32_t)(filesize / 60);
2,385,670✔
689

690
  if (taosLSeekFile(tsLogObj.logHandle->pFile, 0, SEEK_END) < 0) {
2,385,670✔
691
    TAOS_CHECK_EXIT(terrno);
×
692
  }
693

694
  (void)snprintf(name, sizeof(name),
2,385,670✔
695
                 "==================================================\n"
696
                 "                new log file\n"
697
                 "==================================================\n");
698
  if (taosWriteFile(tsLogObj.logHandle->pFile, name, (uint32_t)strlen(name)) <= 0) {
2,385,670✔
699
    TAOS_CHECK_EXIT(terrno);
×
700
  }
701

702
_exit:
2,385,670✔
703
  if (code != 0) {
2,385,670✔
704
    taosUnLockLogFile(tsLogObj.logHandle->pFile);
×
705
    TAOS_UNUSED(printf("failed to init normal log file:%s at line %d, reason:%s\n", name, lino, tstrerror(code)));
×
706
    SET_ERROR_MSG("failed to init normal log file:%s at line %d, reason:%s", name, lino, tstrerror(code));
×
707
  }
708
  return code;
2,385,670✔
709
}
710

711
static void taosUpdateLogNums(ELogLevel level) {
2,147,483,647✔
712
  switch (level) {
2,147,483,647✔
713
    case DEBUG_ERROR:
651,668,559✔
714
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfErrorLogs, 1));
651,668,559✔
715
      break;
651,713,532✔
716
    case DEBUG_INFO:
2,147,483,647✔
717
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfInfoLogs, 1));
2,147,483,647✔
718
      break;
2,147,483,647✔
719
    case DEBUG_DEBUG:
2,147,483,647✔
720
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfDebugLogs, 1));
2,147,483,647✔
721
      break;
2,147,483,647✔
722
    case DEBUG_DUMP:
2,147,483,647✔
723
    case DEBUG_TRACE:
724
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfTraceLogs, 1));
2,147,483,647✔
725
      break;
2,147,483,647✔
726
    default:
×
727
      break;
×
728
  }
729
}
2,147,483,647✔
730

731
static inline int32_t taosBuildLogHead(char *buffer, const char *flags) {
2,147,483,647✔
732
  struct tm      Tm, *ptm;
2,147,483,647✔
733
  struct timeval timeSecs;
2,147,483,647✔
734

735
  TAOS_UNUSED(taosGetTimeOfDay(&timeSecs));
2,147,483,647✔
736
  time_t curTime = timeSecs.tv_sec;
2,147,483,647✔
737
  ptm = taosLocalTime(&curTime, &Tm, NULL, 0, NULL);
2,147,483,647✔
738
  if (ptm == NULL) {
2,147,483,647✔
739
    uError("%s failed to get local time, code:%d", __FUNCTION__, ERRNO);
×
740
    return 0;
×
741
  }
742
  return snprintf(buffer, LOG_MAX_STACK_LINE_BUFFER_SIZE, "%02d/%02d %02d:%02d:%02d.%06d %08" PRId64 " %s %s",
2,147,483,647✔
743
                  ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int32_t)timeSecs.tv_usec,
2,147,483,647✔
744
                  taosGetSelfPthreadId(), LOG_EDITION_FLG, flags);
745
}
746

747
static inline void taosPrintLogImp(ELogLevel level, int32_t dflag, const char *buffer, int32_t len) {
2,147,483,647✔
748
  if ((dflag & DEBUG_FILE) && tsLogObj.logHandle && tsLogObj.logHandle->pFile != NULL && osLogSpaceSufficient()) {
2,147,483,647✔
749
    taosUpdateLogNums(level);
2,147,483,647✔
750
    if (tsAsyncLog) {
2,147,483,647✔
751
      TAOS_UNUSED(taosPushLogBuffer(tsLogObj.logHandle, buffer, len));
942,645,488✔
752
    } else {
753
      TAOS_UNUSED(taosWriteFile(tsLogObj.logHandle->pFile, buffer, len));
2,147,483,647✔
754
    }
755

756
    if (tsNumOfLogLines > 0) {
2,147,483,647✔
757
      TAOS_UNUSED(atomic_add_fetch_32(&tsLogObj.lines, 1));
2,147,483,647✔
758
      if ((tsLogObj.lines > tsNumOfLogLines) && (tsLogObj.openInProgress == 0)) {
2,147,483,647✔
759
        TAOS_UNUSED(taosOpenNewLogFile());
98✔
760
      }
761
    }
762
  }
763

764
  int fd = 0;
2,147,483,647✔
765
  if (tsLogObj.outputType == LOG_OUTPUT_FILE) {
2,147,483,647✔
766
#ifndef TAOSD_INTEGRATED    
767
    if (dflag & DEBUG_SCREEN) fd = 1;
2,147,483,647✔
768
#else
769
    if ((dflag & DEBUG_SCREEN) && tsLogEmbedded) fd = 1;
770
#endif
UNCOV
771
  } else if (tsLogObj.outputType == LOG_OUTPUT_STDOUT) {
×
UNCOV
772
    fd = 1;
×
UNCOV
773
  } else if (tsLogObj.outputType == LOG_OUTPUT_STDERR) {
×
UNCOV
774
    fd = 2;
×
775
  }
776

777
  if (fd) {
2,147,483,647✔
778
#pragma GCC diagnostic push
779
#pragma GCC diagnostic ignored "-Wunused-result"
780
#ifndef TD_ASTRA
781
    if (write(fd, buffer, (uint32_t)len) < 0) {
2,147,483,647✔
782
      TAOS_UNUSED(printf("failed to write log to screen, reason:%s\n", strerror(ERRNO)));
254,150,346✔
783
    }
784
#else
785
    TAOS_UNUSED(fprintf(fd == 1 ? stdout : stderr, "%s", buffer));
786
#endif
787
#pragma GCC diagnostic pop
788
  }
789
}
2,147,483,647✔
790

791
/*
792
  use taosPrintLogImpl_useStackBuffer to avoid stack overflow
793

794
*/
795
static int8_t taosPrintLogImplUseStackBuffer(const char *flags, int32_t level, int32_t dflag, const char *format,
2,147,483,647✔
796
                                             va_list args) {
797
  char    buffer[LOG_MAX_STACK_LINE_BUFFER_SIZE];
2,147,483,647✔
798
  int32_t len = taosBuildLogHead(buffer, flags);
2,147,483,647✔
799

800
  int32_t writeLen = len + vsnprintf(buffer + len, LOG_MAX_STACK_LINE_BUFFER_SIZE - len - 1, format, args);
2,147,483,647✔
801
  if (writeLen > LOG_MAX_STACK_LINE_SIZE) {
2,147,483,647✔
802
    return 1;
247,798,854✔
803
  }
804

805
  buffer[writeLen++] = '\n';
2,147,483,647✔
806
  buffer[writeLen] = 0;
2,147,483,647✔
807

808
  taosPrintLogImp(level, dflag, buffer, writeLen);
2,147,483,647✔
809

810
  if (tsLogFp && level <= DEBUG_INFO) {
2,147,483,647✔
811
    buffer[writeLen - 1] = 0;
2,147,483,647✔
812
    (*tsLogFp)(taosGetTimestampMs(), level, buffer + len);
2,147,483,647✔
813
  }
814
  return 0;
2,147,483,647✔
815
}
816
static int8_t taosPrintLogImplUseHeapBuffer(const char *flags, int32_t level, int32_t dflag, const char *format,
247,793,953✔
817
                                            va_list args) {
818
  char *buffer = taosMemoryCalloc(1, LOG_MAX_LINE_BUFFER_SIZE + 1);
247,793,953✔
819
  if (buffer == NULL) {
247,802,828✔
820
    return 1;
×
821
  }
822
  int32_t len = taosBuildLogHead(buffer, flags);
247,802,828✔
823

824
  int32_t writeLen = len + vsnprintf(buffer + len, LOG_MAX_LINE_BUFFER_SIZE - len - 1, format, args);
247,814,450✔
825

826
  if (writeLen > LOG_MAX_LINE_SIZE) writeLen = LOG_MAX_LINE_SIZE;
247,806,670✔
827
  buffer[writeLen++] = '\n';
247,806,670✔
828
  buffer[writeLen] = 0;
247,813,843✔
829

830
  taosPrintLogImp(level, dflag, buffer, writeLen);
247,810,149✔
831

832
  if (tsLogFp && level <= DEBUG_INFO) {
247,819,072✔
833
    buffer[writeLen - 1] = 0;
22,745,644✔
834
    (*tsLogFp)(taosGetTimestampMs(), level, buffer + len);
45,491,288✔
835
  }
836
  taosMemoryFree(buffer);
247,819,072✔
837
  return 0;
247,818,722✔
838
}
839
void taosPrintLog(const char *flags, int32_t level, int32_t dflag, const char *format, ...) {
2,147,483,647✔
840
  if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return;
2,147,483,647✔
841

842
  va_list argpointer, argpointer_copy;
2,147,483,647✔
843
  va_start(argpointer, format);
2,147,483,647✔
844
  va_copy(argpointer_copy, argpointer);
2,147,483,647✔
845

846
  if (taosPrintLogImplUseStackBuffer(flags, level, dflag, format, argpointer) == 0) {
2,147,483,647✔
847
  } else {
848
    TAOS_UNUSED(taosPrintLogImplUseHeapBuffer(flags, level, dflag, format, argpointer_copy));
247,792,510✔
849
  }
850
  va_end(argpointer_copy);
2,147,483,647✔
851
  va_end(argpointer);
2,147,483,647✔
852
}
853

854
void taosPrintLongString(const char *flags, int32_t level, int32_t dflag, const char *format, ...) {
668,454,461✔
855
  if (!osLogSpaceSufficient()) return;
668,454,461✔
856
  if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return;
668,454,868✔
857

858
  char *buffer = taosMemoryMalloc(LOG_MAX_LINE_DUMP_BUFFER_SIZE);
668,454,868✔
859
  if (!buffer) return;
668,455,583✔
860
  int32_t len = taosBuildLogHead(buffer, flags);
668,455,583✔
861

862
  va_list argpointer;
665,814,289✔
863
  va_start(argpointer, format);
668,452,943✔
864
  len += vsnprintf(buffer + len, LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 - len, format, argpointer);
668,452,943✔
865
  va_end(argpointer);
668,453,377✔
866

867
  len = len > LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 ? LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 : len;
668,453,377✔
868
  buffer[len++] = '\n';
668,453,377✔
869
  buffer[len] = 0;
668,454,381✔
870

871
  taosPrintLogImp(level, dflag, buffer, len);
668,454,716✔
872
  taosMemoryFree(buffer);
668,455,583✔
873
}
874

875
void taosPrintSlowLog(const char *format, ...) {
152,192✔
876
  if (!osLogSpaceSufficient()) return;
152,192✔
877

878
  int64_t delta = taosGetTimestampSec() - tsLogObj.timestampToday;
152,192✔
879
  if (delta >= 86400 || delta < 0) {
152,192✔
880
    taosOpenNewSlowLogFile();
×
881
  }
882

883
  char   *buffer = taosMemoryMalloc(LOG_MAX_LINE_DUMP_BUFFER_SIZE);
152,192✔
884
  int32_t len = taosBuildLogHead(buffer, "");
152,192✔
885

886
  va_list argpointer;
151,688✔
887
  va_start(argpointer, format);
152,192✔
888
  len += vsnprintf(buffer + len, LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 - len, format, argpointer);
152,192✔
889
  va_end(argpointer);
152,192✔
890

891
  if (len < 0 || len > LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2) {
152,192✔
892
    len = LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2;
×
893
  }
894
  buffer[len++] = '\n';
152,192✔
895
  buffer[len] = 0;
152,192✔
896

897
  TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfSlowLogs, 1));
152,192✔
898

899
  if (tsAsyncLog) {
152,192✔
900
    TAOS_UNUSED(taosPushLogBuffer(tsLogObj.slowHandle, buffer, len));
132✔
901
  } else {
902
    TAOS_UNUSED(taosWriteFile(tsLogObj.slowHandle->pFile, buffer, len));
152,060✔
903
  }
904

905
  taosMemoryFree(buffer);
152,192✔
906
}
907

908
static void taosCloseLogByFd(TdFilePtr pFile) {
98✔
909
  if (pFile != NULL) {
98✔
910
    taosUnLockLogFile(pFile);
98✔
911
    (void)taosCloseFile(&pFile);
98✔
912
  }
913
}
98✔
914

915
static SLogBuff *taosLogBuffNew(int32_t bufSize) {
4,770,533✔
916
  SLogBuff *pLogBuf = NULL;
4,770,533✔
917

918
  pLogBuf = taosMemoryCalloc(1, sizeof(SLogBuff));
4,770,533✔
919
  if (pLogBuf == NULL) return NULL;
4,770,533✔
920

921
  LOG_BUF_BUFFER(pLogBuf) = taosMemoryMalloc(bufSize);
4,770,533✔
922
  if (LOG_BUF_BUFFER(pLogBuf) == NULL) goto _err;
4,770,533✔
923

924
  LOG_BUF_START(pLogBuf) = LOG_BUF_END(pLogBuf) = 0;
4,770,533✔
925
  LOG_BUF_SIZE(pLogBuf) = bufSize;
4,770,533✔
926
  pLogBuf->minBuffSize = bufSize / 10;
4,770,533✔
927
  pLogBuf->stop = 0;
4,770,533✔
928
  pLogBuf->writeInterval = LOG_DEFAULT_INTERVAL;
4,770,533✔
929
  pLogBuf->lock = 0;
4,770,533✔
930
  if (taosThreadMutexInit(&LOG_BUF_MUTEX(pLogBuf), NULL) < 0) goto _err;
4,770,533✔
931
  // tsem_init(&(pLogBuf->buffNotEmpty), 0, 0);
932

933
  return pLogBuf;
4,770,533✔
934

935
_err:
×
936
  taosMemoryFreeClear(LOG_BUF_BUFFER(pLogBuf));
×
937
  taosMemoryFreeClear(pLogBuf);
×
938
  return NULL;
×
939
}
940

941
static void taosCopyLogBuffer(SLogBuff *pLogBuf, int32_t start, int32_t end, const char *msg, int32_t msgLen) {
942,721,721✔
942
  if (start > end) {
942,721,721✔
943
    memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, msgLen);
411,337✔
944
  } else {
945
    if (LOG_BUF_SIZE(pLogBuf) - end < msgLen) {
942,310,384✔
946
      memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, LOG_BUF_SIZE(pLogBuf) - end);
2,248✔
947
      memcpy(LOG_BUF_BUFFER(pLogBuf), msg + LOG_BUF_SIZE(pLogBuf) - end, msgLen - LOG_BUF_SIZE(pLogBuf) + end);
2,248✔
948
    } else {
949
      memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, msgLen);
942,308,136✔
950
    }
951
  }
952
  LOG_BUF_END(pLogBuf) = (LOG_BUF_END(pLogBuf) + msgLen) % LOG_BUF_SIZE(pLogBuf);
942,721,721✔
953
}
942,721,721✔
954

955
static int32_t taosPushLogBuffer(SLogBuff *pLogBuf, const char *msg, int32_t msgLen) {
942,467,955✔
956
  int32_t        start = 0;
942,467,955✔
957
  int32_t        end = 0;
942,467,955✔
958
  int32_t        remainSize = 0;
942,467,955✔
959
  static int64_t lostLine = 0;
960
  char           tmpBuf[128];
941,570,732✔
961
  int32_t        tmpBufLen = 0;
942,526,185✔
962

963
  if (pLogBuf == NULL || pLogBuf->stop) return -1;
942,526,185✔
964

965
  (void)taosThreadMutexLock(&LOG_BUF_MUTEX(pLogBuf));
942,534,485✔
966
  start = LOG_BUF_START(pLogBuf);
942,721,721✔
967
  end = LOG_BUF_END(pLogBuf);
942,721,721✔
968

969
  remainSize = (start > end) ? (start - end - 1) : (start + LOG_BUF_SIZE(pLogBuf) - end - 1);
942,721,721✔
970

971
  if (lostLine > 0) {
942,721,721✔
972
    tmpBufLen = snprintf(tmpBuf, tListLen(tmpBuf), "...Lost %" PRId64 " lines here...\n", lostLine);
×
973
  }
974

975
  if (remainSize <= msgLen || ((lostLine > 0) && (remainSize <= (msgLen + tmpBufLen)))) {
942,721,721✔
976
    lostLine++;
×
977
    tsAsyncLogLostLines++;
×
978
    (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
×
979
    return -1;
×
980
  }
981

982
  if (lostLine > 0) {
942,721,721✔
983
    taosCopyLogBuffer(pLogBuf, start, end, tmpBuf, tmpBufLen);
×
984
    lostLine = 0;
×
985
  }
986

987
  taosCopyLogBuffer(pLogBuf, LOG_BUF_START(pLogBuf), LOG_BUF_END(pLogBuf), msg, msgLen);
942,721,721✔
988

989
  // int32_t w = atomic_sub_fetch_32(&waitLock, 1);
990
  /*
991
  if (w <= 0 || ((remainSize - msgLen - tmpBufLen) < (LOG_BUF_SIZE(pLogBuf) * 4 /5))) {
992
    tsem_post(&(pLogBuf->buffNotEmpty));
993
    dbgPostN++;
994
  } else {
995
    dbgNoPostN++;
996
  }
997
  */
998

999
  (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
942,721,721✔
1000

1001
  return 0;
942,712,447✔
1002
}
1003

1004
static int32_t taosGetLogRemainSize(SLogBuff *pLogBuf, int32_t start, int32_t end) {
206,137,991✔
1005
  int32_t rSize = end - start;
206,137,991✔
1006

1007
  return rSize >= 0 ? rSize : LOG_BUF_SIZE(pLogBuf) + rSize;
206,137,991✔
1008
}
1009

1010
static void taosWriteSlowLog(SLogBuff *pLogBuf) {
2,147,483,647✔
1011
  int32_t lock = atomic_val_compare_exchange_32(&pLogBuf->lock, 0, 1);
2,147,483,647✔
1012
  if (lock == 1) return;
2,147,483,647✔
1013
  taosWriteLog(pLogBuf);
2,147,483,647✔
1014
  atomic_store_32(&pLogBuf->lock, 0);
2,147,483,647✔
1015
}
1016
static void taosWriteLog(SLogBuff *pLogBuf) {
2,147,483,647✔
1017
  (void)taosThreadMutexLock(&LOG_BUF_MUTEX(pLogBuf));
2,147,483,647✔
1018
  int32_t start = LOG_BUF_START(pLogBuf);
2,147,483,647✔
1019
  int32_t end = LOG_BUF_END(pLogBuf);
2,147,483,647✔
1020
  (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
2,147,483,647✔
1021

1022
  if (start == end) {
2,147,483,647✔
1023
    dbgEmptyW++;
2,147,483,647✔
1024
    pLogBuf->writeInterval = LOG_MAX_INTERVAL;
2,147,483,647✔
1025
    return;
2,147,483,647✔
1026
  }
1027

1028
  int32_t pollSize = taosGetLogRemainSize(pLogBuf, start, end);
200,698,455✔
1029
  if (pollSize < pLogBuf->minBuffSize) {
200,698,455✔
1030
    pLogBuf->lastDuration += pLogBuf->writeInterval;
200,698,455✔
1031
    if (pLogBuf->lastDuration < LOG_MAX_WAIT_MSEC) {
200,698,455✔
1032
      return;
195,258,919✔
1033
    }
1034
  }
1035

1036
  pLogBuf->lastDuration = 0;
5,439,536✔
1037

1038
  if (start < end) {
5,439,536✔
1039
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf) + start, pollSize));
5,437,288✔
1040
  } else {
1041
    int32_t tsize = LOG_BUF_SIZE(pLogBuf) - start;
2,248✔
1042
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf) + start, tsize));
2,248✔
1043

1044
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf), end));
2,248✔
1045
  }
1046

1047
  dbgWN++;
5,439,536✔
1048
  dbgWSize += pollSize;
5,439,536✔
1049

1050
  if (pollSize < pLogBuf->minBuffSize) {
5,439,536✔
1051
    dbgSmallWN++;
5,439,536✔
1052
    if (pLogBuf->writeInterval < LOG_MAX_INTERVAL) {
5,439,536✔
1053
      pLogBuf->writeInterval += LOG_INTERVAL_STEP;
×
1054
    }
1055
  } else if (pollSize > LOG_BUF_SIZE(pLogBuf) / 3) {
×
1056
    dbgBigWN++;
×
1057
    pLogBuf->writeInterval = LOG_MIN_INTERVAL;
×
1058
  } else if (pollSize > LOG_BUF_SIZE(pLogBuf) / 4) {
×
1059
    if (pLogBuf->writeInterval > LOG_MIN_INTERVAL) {
×
1060
      pLogBuf->writeInterval -= LOG_INTERVAL_STEP;
×
1061
    }
1062
  }
1063

1064
  (void)taosThreadMutexLock(&LOG_BUF_MUTEX(pLogBuf));
5,439,536✔
1065
  LOG_BUF_START(pLogBuf) = (LOG_BUF_START(pLogBuf) + pollSize) % LOG_BUF_SIZE(pLogBuf);
5,439,536✔
1066

1067
  start = LOG_BUF_START(pLogBuf);
5,439,536✔
1068
  end = LOG_BUF_END(pLogBuf);
5,439,536✔
1069
  (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
5,439,536✔
1070

1071
  pollSize = taosGetLogRemainSize(pLogBuf, start, end);
5,439,536✔
1072
  if (pollSize < pLogBuf->minBuffSize) {
5,439,536✔
1073
    return;
5,439,536✔
1074
  }
1075

1076
  pLogBuf->writeInterval = 0;
×
1077
}
1078

1079
#define LOG_ROTATE_INTERVAL 3600
1080
#if !defined(TD_ENTERPRISE) || defined(ASSERT_NOT_CORE) || defined(GRANTS_CFG)
1081
#define LOG_INACTIVE_TIME 7200
1082
#define LOG_ROTATE_BOOT   900
1083
#else
1084
#define LOG_INACTIVE_TIME 5
1085
#define LOG_ROTATE_BOOT   (LOG_INACTIVE_TIME + 1)
1086
#endif
1087
static int8_t tsLogRotateRunning = 0;
1088
static void  *taosLogRotateFunc(void *param) {
1,514,672✔
1089
  setThreadName("logRotate");
1,514,672✔
1090
  int32_t code = 0;
1,514,672✔
1091
  if (0 != atomic_val_compare_exchange_8(&tsLogRotateRunning, 0, 1)) {
1,514,672✔
1092
    uInfo("log rotation is already in progress");
×
1093
    return NULL;
×
1094
  }
1095
  // get prefix of logfile name
1096
  char *filePrefix = NULL;
1,514,672✔
1097
  char *filePos = strrchr(tsLogObj.logName, TD_DIRSEP_CHAR);
1,514,672✔
1098
  if (!filePos || !(++filePos)) {
1,514,672✔
1099
    atomic_store_8(&tsLogRotateRunning, 0);
×
1100
    return NULL;
×
1101
  }
1102
  int32_t filePrefixLen = strlen(filePos);
1,514,672✔
1103
  if (!(filePrefix = taosMemoryMalloc(filePrefixLen + 1))) {
1,514,672✔
1104
    atomic_store_8(&tsLogRotateRunning, 0);
×
1105
    return NULL;
×
1106
  }
1107
  tstrncpy(filePrefix, filePos, filePrefixLen + 1);
1,514,672✔
1108
  int32_t i = filePrefixLen - 1;
1,514,672✔
1109
  while (i > 0 && isdigit(filePrefix[i])) filePrefix[i--] = '\0';
1,910,921✔
1110

1111
  taosWLockLatch(&tsLogRotateLatch);
1,514,672✔
1112
  // compress or remove the old log files
1113
  TdDirPtr pDir = taosOpenDir(tsLogDir);
1,514,672✔
1114
  if (!pDir) goto _exit;
1,514,672✔
1115
  TdDirEntryPtr de = NULL;
1,514,672✔
1116
  while ((de = taosReadDir(pDir))) {
9,099,788✔
1117
    if (taosDirEntryIsDir(de)) {
7,585,116✔
1118
      continue;
3,073,061✔
1119
    }
1120
    char *fname = taosGetDirEntryName(de);
4,555,772✔
1121
    if (!fname) {
4,555,772✔
1122
      continue;
×
1123
    }
1124

1125
    if (!strstr(fname, filePrefix)) continue;
4,555,772✔
1126

1127
    char *pSec = strrchr(fname, '.');
1,651,801✔
1128
    if (!pSec) {
1,651,801✔
1129
      continue;
×
1130
    }
1131
    char *pIter = pSec;
1,651,801✔
1132
    bool  isSec = true;
1,651,801✔
1133
    while (*(++pIter)) {
3,303,602✔
1134
      if (!isdigit(*pIter)) {
1,651,801✔
1135
        isSec = false;
×
1136
        break;
×
1137
      }
1138
    }
1139
    if (!isSec) {
1,651,801✔
1140
      continue;
×
1141
    }
1142

1143
    int64_t fileSec = 0;
1,651,801✔
1144
    if ((code = taosStr2int64(pSec + 1, &fileSec)) != 0) {
1,651,801✔
1145
      uWarn("%s:%d failed to convert %s to int64 since %s", __func__, __LINE__, pSec + 1, tstrerror(code));
×
1146
      continue;
×
1147
    }
1148
    if (fileSec <= 100) {
1,651,801✔
1149
      continue;
1,651,801✔
1150
    }
1151

1152
    char fullName[PATH_MAX] = {0};
×
1153
    snprintf(fullName, sizeof(fullName), "%s%s%s", tsLogDir, TD_DIRSEP, fname);
×
1154

1155
    int64_t mtime = 0;
×
1156
    if ((code = taosStatFile(fullName, NULL, &mtime, NULL)) != 0) {
×
1157
      uWarn("%s:%d failed to stat file %s since %s", __func__, __LINE__, fullName, tstrerror(code));
×
1158
      continue;
×
1159
    }
1160

1161
    int64_t inactiveSec = taosGetTimestampMs() / 1000 - mtime;
×
1162

1163
    if (inactiveSec < LOG_INACTIVE_TIME) {
×
1164
      continue;
×
1165
    }
1166

1167
    int32_t days = inactiveSec / 86400 + 1;
×
1168
    if (tsLogKeepDays != 0 && days > abs(tsLogKeepDays)) {
×
1169
      TAOS_UNUSED(taosRemoveFile(fullName));
×
1170
      uInfo("file:%s is removed, days:%d, keepDays:%d, sed:%" PRId64, fullName, days, tsLogKeepDays, fileSec);
×
1171
    } else {
1172
      taosKeepOldLog(fullName);  // compress
×
1173
    }
1174
  }
1175
  if ((code = taosCloseDir(&pDir)) != 0) {
1,514,672✔
1176
    uWarn("%s:%d failed to close dir %s since %s\n", __func__, __LINE__, tsLogDir, tstrerror(code));
×
1177
  }
1178

1179
  if (tsLogKeepDays != 0) {
1,514,672✔
1180
    taosRemoveOldFiles(tsLogDir, abs(tsLogKeepDays));
244✔
1181
  }
1182
_exit:
1,514,672✔
1183
  taosWUnLockLatch(&tsLogRotateLatch);
1,514,672✔
1184
  atomic_store_8(&tsLogRotateRunning, 0);
1,514,672✔
1185
  taosMemFreeClear(filePrefix);
1,514,672✔
1186
  return NULL;
1,514,672✔
1187
}
1188

1189
static void *taosAsyncOutputLog(void *param) {
2,385,670✔
1190
  SLogBuff *pLogBuf = (SLogBuff *)tsLogObj.logHandle;
2,385,670✔
1191
  SLogBuff *pSlowBuf = (SLogBuff *)tsLogObj.slowHandle;
2,385,670✔
1192

1193
  setThreadName("log");
2,385,670✔
1194
  int32_t count = 0;
2,385,670✔
1195
  int32_t updateCron = 0;
2,385,670✔
1196
  int32_t writeInterval = 0;
2,385,670✔
1197
  int64_t lastCheckSec = taosGetTimestampMs() / 1000 - (LOG_ROTATE_INTERVAL - LOG_ROTATE_BOOT);
2,385,670✔
1198

1199
  while (1) {
2,147,483,647✔
1200
    if (pSlowBuf) {
2,147,483,647✔
1201
      writeInterval = TMIN(pLogBuf->writeInterval, pSlowBuf->writeInterval);
2,147,483,647✔
1202
    } else {
1203
      writeInterval = pLogBuf->writeInterval;
9,024✔
1204
    }
1205
    count += writeInterval;
2,147,483,647✔
1206
    updateCron++;
2,147,483,647✔
1207
    taosMsleep(writeInterval);
2,147,483,647✔
1208
    if (count > 1000) {
2,147,483,647✔
1209
      TAOS_UNUSED(osUpdate());
122,706,314✔
1210
      count = 0;
122,706,314✔
1211
    }
1212

1213
    // Polling the buffer
1214
    taosWriteLog(pLogBuf);
2,147,483,647✔
1215
    if (pSlowBuf) taosWriteSlowLog(pSlowBuf);
2,147,483,647✔
1216

1217
    if (pLogBuf->stop || (pSlowBuf && pSlowBuf->stop)) {
2,147,483,647✔
1218
      pLogBuf->lastDuration = LOG_MAX_WAIT_MSEC;
2,385,612✔
1219
      taosWriteLog(pLogBuf);
2,385,612✔
1220
      if (pSlowBuf) taosWriteSlowLog(pSlowBuf);
2,385,612✔
1221
      break;
2,385,612✔
1222
    }
1223

1224
    // process the log rotation every LOG_ROTATE_INTERVAL
1225
    int64_t curSec = taosGetTimestampMs() / 1000;
2,147,483,647✔
1226
    if (curSec >= lastCheckSec) {
2,147,483,647✔
1227
      if ((curSec - lastCheckSec) >= (LOG_ROTATE_INTERVAL + (taosRand() % LOG_ROTATE_BOOT))) {
2,147,483,647✔
1228
        TdThread     thread;
1,506,509✔
1229
        TdThreadAttr attr;
1,506,509✔
1230
        (void)taosThreadAttrInit(&attr);
1,514,672✔
1231
        (void)taosThreadAttrSetDetachState(&attr, PTHREAD_CREATE_DETACHED);
1,514,672✔
1232
#ifdef TD_COMPACT_OS
1233
        (void)taosThreadAttrSetStackSize(&attr, STACK_SIZE_SMALL);
1234
#endif
1235
        if (taosThreadCreate(&thread, &attr, taosLogRotateFunc, tsLogObj.logHandle) == 0) {
1,514,672✔
1236
          uInfo("process log rotation");
1,514,672✔
1237
          lastCheckSec = curSec;
1,514,672✔
1238
        } else {
1239
          uWarn("failed to create thread to process log rotation");
×
1240
        }
1241
        (void)taosThreadAttrDestroy(&attr);
1,514,672✔
1242
      }
1243
    } else if (curSec < lastCheckSec) {
×
1244
      lastCheckSec = curSec;
×
1245
    }
1246
  }
1247

1248
  return NULL;
2,385,612✔
1249
}
1250

1251
bool taosAssertDebug(bool condition, const char *file, int32_t line, bool core, const char *format, ...) {
×
1252
  if (condition) return false;
×
1253

1254
  const char *flags = "UTL FATAL ";
×
1255
  ELogLevel   level = DEBUG_FATAL;
×
1256
  int32_t     dflag = 255;  // tsLogEmbedded ? 255 : uDebugFlag
×
1257
  char        buffer[LOG_MAX_LINE_BUFFER_SIZE];
×
1258
  int32_t     len = taosBuildLogHead(buffer, flags);
×
1259

1260
  va_list argpointer;
×
1261
  va_start(argpointer, format);
×
1262
  len = len + vsnprintf(buffer + len, LOG_MAX_LINE_BUFFER_SIZE - len, format, argpointer);
×
1263
  va_end(argpointer);
×
1264
  buffer[len++] = '\n';
×
1265
  buffer[len] = 0;
×
1266
  taosPrintLogImp(1, 255, buffer, len);
×
1267

1268
  taosPrintLog(flags, level, dflag, "tAssert at file %s:%d exit:%d", file, line, tsAssert);
×
1269
#ifndef TD_ASTRA
1270
  taosPrintTrace(flags, level, dflag, -1);
×
1271
#endif
1272
  if (tsAssert || core) {
×
1273
    taosCloseLog();
×
1274
    taosMsleep(300);
×
1275

1276
#ifdef NDEBUG
1277
    abort();
1278
#else
1279
    assert(0);
×
1280
#endif
1281
  }
1282

1283
  return true;
×
1284
}
1285
#ifdef USE_REPORT
1286
void taosLogCrashInfo(char *nodeType, char *pMsg, int64_t msgLen, int signum, void *sigInfo) {
×
1287
  const char *flags = "UTL FATAL ";
×
1288
  ELogLevel   level = DEBUG_FATAL;
×
1289
  int32_t     dflag = 255;
×
1290
  char        filepath[PATH_MAX] = {0};
×
1291
  TdFilePtr   pFile = NULL;
×
1292

1293
  if (pMsg && msgLen > 0) {
×
1294
    snprintf(filepath, sizeof(filepath), "%s%s.%sCrashLog", tsLogDir, TD_DIRSEP, nodeType);
×
1295

1296
    pFile = taosOpenFile(filepath, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_APPEND);
×
1297
    if (pFile == NULL) {
×
1298
      taosPrintLog(flags, level, dflag, "failed to open file:%s since %s", filepath, terrstr());
×
1299
      goto _return;
×
1300
    }
1301

1302
    if (taosLockFile(pFile) < 0) {
×
1303
      taosPrintLog(flags, level, dflag, "failed to lock file:%s since %s", filepath, terrstr());
×
1304
      goto _return;
×
1305
    }
1306

1307
    int64_t writeSize = taosWriteFile(pFile, &msgLen, sizeof(msgLen));
×
1308
    if (sizeof(msgLen) != writeSize) {
×
1309
      TAOS_UNUSED(taosUnLockFile(pFile));
×
1310
      taosPrintLog(flags, level, dflag, "failed to write len to file:%s,%p wlen:%" PRId64 " tlen:%lu since %s",
×
1311
                   filepath, pFile, writeSize, sizeof(msgLen), terrstr());
1312
      goto _return;
×
1313
    }
1314

1315
    writeSize = taosWriteFile(pFile, pMsg, msgLen);
×
1316
    if (msgLen != writeSize) {
×
1317
      TAOS_UNUSED(taosUnLockFile(pFile));
×
1318
      taosPrintLog(flags, level, dflag, "failed to write file:%s,%p wlen:%" PRId64 " tlen:%" PRId64 " since %s",
×
1319
                   filepath, pFile, writeSize, msgLen, terrstr());
1320
      goto _return;
×
1321
    }
1322

1323
    TAOS_UNUSED(taosUnLockFile(pFile));
×
1324
  }
1325

1326
_return:
×
1327

1328
  if (pFile) (void)taosCloseFile(&pFile);
×
1329

1330
  taosPrintLog(flags, level, dflag, "crash signal is %d", signum);
×
1331

1332
// print the stack trace
1333
#if 0
1334
#ifdef _TD_DARWIN_64
1335
  taosPrintTrace(flags, level, dflag, 4);
1336
#elif !defined(WINDOWS)
1337
  taosPrintLog(flags, level, dflag, "sender PID:%d cmdline:%s", ((siginfo_t *)sigInfo)->si_pid,
1338
               taosGetCmdlineByPID(((siginfo_t *)sigInfo)->si_pid));
1339
  taosPrintTrace(flags, level, dflag, 3);
1340
#else
1341
  taosPrintTrace(flags, level, dflag, 8);
1342
#endif
1343
#endif
1344
  taosMemoryFree(pMsg);
×
1345
}
×
1346

1347
typedef enum {
1348
  CRASH_LOG_WRITER_UNKNOWN = 0,
1349
  CRASH_LOG_WRITER_INIT = 1,
1350
  CRASH_LOG_WRITER_WAIT,
1351
  CRASH_LOG_WRITER_RUNNING,
1352
  CRASH_LOG_WRITER_QUIT
1353
} CrashStatus;
1354
typedef struct crashBasicInfo {
1355
  int8_t  status;
1356
  int64_t clusterId;
1357
  int64_t startTime;
1358
  char   *nodeType;
1359
  int     signum;
1360
  void   *sigInfo;
1361
  tsem_t  sem;
1362
  int64_t reportThread;
1363
} crashBasicInfo;
1364

1365
crashBasicInfo gCrashBasicInfo = {0};
1366

1367
void setCrashWriterStatus(int8_t status) { atomic_store_8(&gCrashBasicInfo.status, status); }
×
1368
bool reportThreadSetQuit() {
×
1369
  CrashStatus status =
×
1370
      atomic_val_compare_exchange_8(&gCrashBasicInfo.status, CRASH_LOG_WRITER_INIT, CRASH_LOG_WRITER_QUIT);
×
1371
  if (status == CRASH_LOG_WRITER_INIT) {
×
1372
    return true;
×
1373
  } else {
1374
    return false;
×
1375
  }
1376
}
1377

1378
bool setReportThreadWait() {
×
1379
  CrashStatus status =
×
1380
      atomic_val_compare_exchange_8(&gCrashBasicInfo.status, CRASH_LOG_WRITER_INIT, CRASH_LOG_WRITER_WAIT);
×
1381
  if (status == CRASH_LOG_WRITER_INIT) {
×
1382
    return true;
×
1383
  } else {
1384
    return false;
×
1385
  }
1386
}
1387
bool setReportThreadRunning() {
×
1388
  CrashStatus status =
×
1389
      atomic_val_compare_exchange_8(&gCrashBasicInfo.status, CRASH_LOG_WRITER_WAIT, CRASH_LOG_WRITER_RUNNING);
×
1390
  if (status == CRASH_LOG_WRITER_WAIT) {
×
1391
    return true;
×
1392
  } else {
1393
    return false;
×
1394
  }
1395
}
1396
static void checkWriteCrashLogToFileInNewThead() {
×
1397
  if (setReportThreadRunning()) {
×
1398
    char       *pMsg = NULL;
×
1399
    const char *flags = "UTL FATAL ";
×
1400
    ELogLevel   level = DEBUG_FATAL;
×
1401
    int32_t     dflag = 255;
×
1402
    int64_t     msgLen = -1;
×
1403

1404
    if (tsEnableCrashReport) {
×
1405
      if (taosGenCrashJsonMsg(gCrashBasicInfo.signum, &pMsg, gCrashBasicInfo.clusterId, gCrashBasicInfo.startTime)) {
×
1406
        taosPrintLog(flags, level, dflag, "failed to generate crash json msg");
×
1407
      } else {
1408
        msgLen = strlen(pMsg);
×
1409
      }
1410
    }
1411
    taosLogCrashInfo(gCrashBasicInfo.nodeType, pMsg, msgLen, gCrashBasicInfo.signum, gCrashBasicInfo.sigInfo);
×
1412
    setCrashWriterStatus(CRASH_LOG_WRITER_INIT);
×
1413
    int32_t code = tsem_post(&gCrashBasicInfo.sem);
×
1414
    if (code != 0 ) {
×
1415
      uError("failed to post sem for crashBasicInfo, code:%d", code);
×
1416
    }
1417
    TAOS_UNUSED(tsem_post(&gCrashBasicInfo.sem));
×
1418
  }
1419
}
×
1420

1421
void checkAndPrepareCrashInfo() {
×
1422
  return checkWriteCrashLogToFileInNewThead();
×
1423
}
1424

1425
int32_t initCrashLogWriter() {
×
1426
  int32_t code = tsem_init(&gCrashBasicInfo.sem, 0, 0);
×
1427
  if (code != 0) {
×
1428
    uError("failed to init sem for crashLogWriter, code:%d", code);
×
1429
    return code;
×
1430
  }
1431
  gCrashBasicInfo.reportThread = taosGetSelfPthreadId();
×
1432
  setCrashWriterStatus(CRASH_LOG_WRITER_INIT);
×
1433
  return code;
×
1434
}
1435

1436
void writeCrashLogToFile(int signum, void *sigInfo, char *nodeType, int64_t clusterId, int64_t startTime) {
×
1437
  if (gCrashBasicInfo.reportThread == taosGetSelfPthreadId()) {
×
1438
    return;
×
1439
  }
1440
  if (setReportThreadWait()) {
×
1441
    gCrashBasicInfo.clusterId = clusterId;
×
1442
    gCrashBasicInfo.startTime = startTime;
×
1443
    gCrashBasicInfo.nodeType = nodeType;
×
1444
    gCrashBasicInfo.signum = signum;
×
1445
    gCrashBasicInfo.sigInfo = sigInfo;
×
1446
    TAOS_UNUSED(tsem_wait(&gCrashBasicInfo.sem));
×
1447
  }
1448
}
1449

1450
void taosReadCrashInfo(char *filepath, char **pMsg, int64_t *pMsgLen, TdFilePtr *pFd) {
×
1451
  const char *flags = "UTL FATAL ";
×
1452
  ELogLevel   level = DEBUG_FATAL;
×
1453
  int32_t     dflag = 255;
×
1454
  TdFilePtr   pFile = NULL;
×
1455
  bool        truncateFile = false;
×
1456
  char       *buf = NULL;
×
1457

1458
  if (NULL == *pFd) {
×
1459
    int64_t filesize = 0;
×
1460
    if (taosStatFile(filepath, &filesize, NULL, NULL) < 0) {
×
1461
      if (TAOS_SYSTEM_ERROR(ENOENT) == terrno) {
×
1462
        return;
×
1463
      }
1464

1465
      taosPrintLog(flags, level, dflag, "failed to stat file:%s since %s", filepath, terrstr());
×
1466
      return;
×
1467
    }
1468

1469
    if (filesize <= 0) {
×
1470
      return;
×
1471
    }
1472

1473
    pFile = taosOpenFile(filepath, TD_FILE_READ | TD_FILE_WRITE);
×
1474
    if (pFile == NULL) {
×
1475
      if (ENOENT == ERRNO) {
×
1476
        return;
×
1477
      }
1478

1479
      taosPrintLog(flags, level, dflag, "failed to open file:%s since %s", filepath, terrstr());
×
1480
      return;
×
1481
    }
1482

1483
    TAOS_UNUSED(taosLockFile(pFile));
×
1484
  } else {
1485
    pFile = *pFd;
×
1486
  }
1487

1488
  int64_t msgLen = 0;
×
1489
  int64_t readSize = taosReadFile(pFile, &msgLen, sizeof(msgLen));
×
1490
  if (sizeof(msgLen) != readSize) {
×
1491
    truncateFile = true;
×
1492
    if (readSize < 0) {
×
1493
      taosPrintLog(flags, level, dflag, "failed to read len from file:%s,%p wlen:%" PRId64 " tlen:%lu since %s",
×
1494
                   filepath, pFile, readSize, sizeof(msgLen), terrstr());
1495
    }
1496
    goto _return;
×
1497
  }
1498

1499
  buf = taosMemoryMalloc(msgLen);
×
1500
  if (NULL == buf) {
×
1501
    taosPrintLog(flags, level, dflag, "failed to malloc buf, size:%" PRId64, msgLen);
×
1502
    goto _return;
×
1503
  }
1504

1505
  readSize = taosReadFile(pFile, buf, msgLen);
×
1506
  if (msgLen != readSize) {
×
1507
    truncateFile = true;
×
1508
    taosPrintLog(flags, level, dflag, "failed to read file:%s,%p wlen:%" PRId64 " tlen:%" PRId64 " since %s", filepath,
×
1509
                 pFile, readSize, msgLen, terrstr());
1510
    goto _return;
×
1511
  }
1512

1513
  *pMsg = buf;
×
1514
  *pMsgLen = msgLen;
×
1515
  *pFd = pFile;
×
1516

1517
  return;
×
1518

1519
_return:
×
1520

1521
  if (truncateFile) {
×
1522
    TAOS_UNUSED(taosFtruncateFile(pFile, 0));
×
1523
  }
1524
  TAOS_UNUSED(taosUnLockFile(pFile));
×
1525
  TAOS_UNUSED(taosCloseFile(&pFile));
×
1526
  taosMemoryFree(buf);
×
1527

1528
  *pMsg = NULL;
×
1529
  *pMsgLen = 0;
×
1530
  *pFd = NULL;
×
1531
}
1532

1533
void taosReleaseCrashLogFile(TdFilePtr pFile, bool truncateFile) {
×
1534
  if (truncateFile) {
×
1535
    TAOS_UNUSED(taosFtruncateFile(pFile, 0));
×
1536
  }
1537

1538
  TAOS_UNUSED(taosUnLockFile(pFile));
×
1539
  TAOS_UNUSED(taosCloseFile(&pFile));
×
1540
}
×
1541
#endif // USE_REPORT
1542

1543
#ifdef NDEBUG
1544
bool taosAssertRelease(bool condition) {
1545
  if (condition) return false;
1546

1547
  const char *flags = "UTL FATAL ";
1548
  ELogLevel   level = DEBUG_FATAL;
1549
  int32_t     dflag = 255;  // tsLogEmbedded ? 255 : uDebugFlag
1550

1551
  taosPrintLog(flags, level, dflag, "tAssert called in release mode, exit:%d", tsAssert);
1552
  taosPrintTrace(flags, level, dflag, 0);
1553

1554
  if (tsAssert) {
1555
    taosMsleep(300);
1556
    abort();
1557
  }
1558

1559
  return true;
1560
}
1561
#endif
1562

1563
#define NUM_BASE 100
1564
#define DIGIT_LENGTH 2
1565
#define MAX_DIGITS 24
1566

1567
char* u64toaFastLut(uint64_t val, char* buf) {
2,147,483,647✔
1568
  // Look-up table for 2-digit numbers
1569
  static const char* lut =
1570
      "0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455"
1571
      "5657585960616263646566676869707172737475767778798081828384858687888990919293949596979899";
1572

1573
  char  temp[MAX_DIGITS];
2,147,483,647✔
1574
  char* p = temp + tListLen(temp);
2,147,483,647✔
1575

1576
  // Process the digits greater than or equal to 100
1577
  while (val >= NUM_BASE) {
2,147,483,647✔
1578
    // Get the last 2 digits from the look-up table and add to the buffer
1579
    p -= DIGIT_LENGTH;
2,147,483,647✔
1580
    strncpy(p, lut + (val % NUM_BASE) * DIGIT_LENGTH, DIGIT_LENGTH);
2,147,483,647✔
1581
    val /= NUM_BASE;
2,147,483,647✔
1582
  }
1583

1584
  // Process the remaining 1 or 2 digits
1585
  if (val >= 10) {
2,147,483,647✔
1586
    // If the number is 10 or more, get the 2 digits from the look-up table
1587
    p -= DIGIT_LENGTH;
1,197,209,751✔
1588
    strncpy(p, lut + val * DIGIT_LENGTH, DIGIT_LENGTH);
1,197,467,513✔
1589
  } else if (val > 0 || p == temp) {
1,164,588,419✔
1590
    // If the number is less than 10, add the single digit to the buffer
1591
    p -= 1;
1,164,588,419✔
1592
    *p = val + '0';
1,164,640,833✔
1593
  }
1594

1595
  int64_t len = temp + tListLen(temp) - p;
2,147,483,647✔
1596
  if (len > 0) {
2,147,483,647✔
1597
    memcpy(buf, p, len);
2,147,483,647✔
1598
  } else {
1599
    buf[0] = '0';
×
1600
    len = 1;
×
1601
  }
1602
  buf[len] = '\0';
2,147,483,647✔
1603

1604
  return buf + len;
2,147,483,647✔
1605
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc