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

taosdata / TDengine / #5034

24 Apr 2026 11:25AM UTC coverage: 73.058%. Remained the same
#5034

push

travis-ci

web-flow
merge: from main to 3.0 branch #35224

merge: from main to 3.0 branch[manual-only]

1336 of 1975 new or added lines in 48 files covered. (67.65%)

14149 existing lines in 164 files now uncovered.

275896 of 377640 relevant lines covered (73.06%)

132944440.29 hits per line

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

80.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 int8_t   tsLogNeedRotate = 0;
97
static SLogObj  tsLogObj = {.fileNum = 1, .slowHandle = NULL};
98
static int64_t  tsAsyncLogLostLines = 0;
99
static int32_t  tsDaylightActive; /* Currently in daylight saving time. */
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,919,635✔
164
  TdThreadAttr threadAttr;
2,893,020✔
165
  (void)taosThreadAttrInit(&threadAttr);
2,919,635✔
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,919,635✔
170
    return terrno;
×
171
  }
172
  (void)taosThreadAttrDestroy(&threadAttr);
2,919,635✔
173
  return 0;
2,919,635✔
174
}
175

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

189
static void getFullPathName(char *fullName, const char *logName) {
5,831,263✔
190
  if (strlen(tsLogDir) != 0) {
5,831,263✔
191
    char lastC = tsLogDir[strlen(tsLogDir) - 1];
5,827,293✔
192
    if (lastC == '\\' || lastC == '/') {
5,827,293✔
193
      snprintf(fullName, PATH_MAX,
1,978,229✔
194
               "%s"
195
               "%s",
196
               tsLogDir, logName);
197
    } else {
198
      snprintf(fullName, PATH_MAX, "%s" TD_DIRSEP "%s", tsLogDir, logName);
3,849,064✔
199
    }
200
  } else {
201
    snprintf(fullName, PATH_MAX, "%s", logName);
3,970✔
202
  }
203
}
5,831,263✔
204

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

213
  getFullPathName(tsLogObj.slowLogName, logFileName);
2,911,628✔
214

215
  char    name[PATH_MAX + TD_TIME_STR_LEN] = {0};
2,911,628✔
216
  char    day[TD_TIME_STR_LEN] = {0};
2,911,628✔
217
  int32_t code = getDay(day, sizeof(day));
2,911,628✔
218
  if (code != 0) {
2,911,628✔
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,911,628✔
224

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

229
  TAOS_UNUSED(taosUmaskFile(0));
2,911,628✔
230
  tsLogObj.slowHandle->pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_READ | TD_FILE_WRITE | TD_FILE_APPEND);
2,911,628✔
231
  if (tsLogObj.slowHandle->pFile == NULL) {
2,911,628✔
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,911,628✔
238
}
239

240
int32_t taosInitLogOutput(const char **ppLogName) {
2,917,610✔
241
  const char *pLog = tsLogOutput;
2,917,610✔
242
  const char *pLogName = NULL;
2,917,610✔
243
  if (pLog) {
2,917,610✔
244
    if (!tIsValidFilePath(pLog, NULL)) {
3,402✔
245
      fprintf(stderr, "invalid log output destination:%s, contains illegal char\n", pLog);
420✔
246
      return TSDB_CODE_INVALID_CFG;
420✔
247
    }
248
    if (0 == strcasecmp(pLog, "stdout")) {
2,982✔
249
      tsLogObj.outputType = LOG_OUTPUT_STDOUT;
291✔
250
      if (ppLogName) *ppLogName = pLog;
291✔
251
      return 0;
291✔
252
    }
253
    if (0 == strcasecmp(pLog, "stderr")) {
2,691✔
254
      tsLogObj.outputType = LOG_OUTPUT_STDERR;
217✔
255
      if (ppLogName) *ppLogName = pLog;
217✔
256
      return 0;
217✔
257
    }
258
    if (0 == strcasecmp(pLog, "/dev/null")) {
2,474✔
259
      tsLogObj.outputType = LOG_OUTPUT_NULL;
1,086✔
260
      if (ppLogName) *ppLogName = pLog;
1,086✔
261
      return 0;
1,086✔
262
    }
263
    int32_t len = strlen(pLog);
1,388✔
264
    if (len < 1) {
1,388✔
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);
1,388✔
269
    if (*p == '/' || *p == '\\') {
1,388✔
270
      return 0;
520✔
271
    }
272

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

283
    if (!tIsValidFileName(pLogName, NULL)) {
464✔
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;
464✔
288
  }
289
  return 0;
2,914,672✔
290
}
291

292
int32_t taosInitLog(const char *logName, int32_t maxFiles, bool tsc) {
2,934,039✔
293
  if (atomic_val_compare_exchange_8(&tsLogInited, 0, 1) != 0) return 0;
2,934,039✔
294
  int32_t code = osUpdate();
2,920,623✔
295
  if (code != 0) {
2,920,623✔
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,920,623✔
300
      tsLogObj.outputType == LOG_OUTPUT_NULL) {
2,920,519✔
301
    return 0;
988✔
302
  }
303

304
  TAOS_CHECK_RETURN(taosInitNormalLog(logName, maxFiles));
2,919,635✔
305
  if (tsc) {
2,919,635✔
306
    TAOS_CHECK_RETURN(taosInitSlowLog());
2,911,628✔
307
  }
308
  TAOS_CHECK_RETURN(taosStartLog());
2,919,635✔
309
  return 0;
2,919,635✔
310
}
311

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

314
static void taosStopLog() {
2,922,204✔
315
  if (tsLogObj.logHandle) {
2,922,204✔
316
    tsLogObj.logHandle->stop = 1;
2,918,286✔
317
  }
318
  if (tsLogObj.slowHandle) {
2,922,204✔
319
    tsLogObj.slowHandle->stop = 1;
2,911,566✔
320
  }
321
}
2,922,204✔
322

323
void taosCloseLog() {
2,922,204✔
324
  taosStopLog();
2,922,204✔
325

326
  if (tsLogObj.logHandle != NULL && taosCheckPthreadValid(tsLogObj.logHandle->asyncThread)) {
2,922,204✔
327
    (void)taosThreadJoin(tsLogObj.logHandle->asyncThread, NULL);
2,918,286✔
328
    taosThreadClear(&tsLogObj.logHandle->asyncThread);
2,918,286✔
329
  }
330

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

338
  if (tsLogObj.logHandle != NULL) {
2,922,204✔
339
    tsLogInited = 0;
2,918,286✔
340

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

351
static bool taosLockLogFile(TdFilePtr pFile) {
4,766,054✔
352
  if (pFile == NULL) return false;
4,766,054✔
353

354
  if (tsLogObj.fileNum > 1) {
4,766,054✔
355
    int32_t ret = taosLockFile(pFile);
3,399,132✔
356
    if (ret == 0) {
3,399,132✔
357
      return true;
2,632,994✔
358
    }
359
  }
360

361
  return false;
2,133,060✔
362
}
363

364
static void taosUnLockLogFile(TdFilePtr pFile) {
1,085,472✔
365
  if (pFile == NULL) return;
1,085,472✔
366

367
  if (tsLogObj.fileNum > 1) {
1,085,472✔
368
    int32_t code = taosUnLockFile(pFile);
1,085,417✔
369
    if (code != 0) {
1,085,417✔
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) {
376✔
376
  if (tsLogKeepDays == 0) {
376✔
377
    keepName[0] = 0;
376✔
378
    return;
376✔
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) {
×
396
  if (oldName[0] == 0) {
×
397
    return;
×
398
  }
399

400
  int32_t   code = 0, lino = 0;
×
401
  TdFilePtr oldFile = NULL;
×
402
  if ((oldFile = taosOpenFile(oldName, TD_FILE_READ))) {
×
403
    TAOS_CHECK_GOTO(taosLockFile(oldFile), &lino, _close_file);
×
404
    char compressFileName[PATH_MAX + 20];
×
405
    snprintf(compressFileName, PATH_MAX + 20, "%s.gz", oldName);
×
406
    TAOS_CHECK_GOTO(taosCompressFile(oldFile, compressFileName), &lino, _unlock_file);
×
407

408
  _unlock_file:
×
409
    TAOS_UNUSED(taosUnLockFile(oldFile));
×
410
  _close_file:
×
411
    TAOS_UNUSED(taosCloseFile(&oldFile));
×
412

413
    if (code == TSDB_CODE_SUCCESS) {
×
414
      TAOS_CHECK_GOTO(taosRemoveFile(oldName), &lino, _exit_keep);
×
415
    }
416
  } else {
417
    code = terrno;
×
418
  }
419

420
_exit_keep:
×
421
  if (code != 0 && tsLogEmbedded == 1) {  // print error messages only in embedded log mode
×
422
    // avoid using uWarn or uError, as they may open a new log file and potentially cause a deadlock.
423
    fprintf(stderr, "WARN: failed at line %d to keep old log file:%s, reason:%s\n", lino, oldName, tstrerror(code));
×
424
  }
425
}
426
typedef struct {
427
  TdFilePtr pOldFile;
428
  char      keepName[PATH_MAX + 20];
429
} OldFileKeeper;
430
static OldFileKeeper *taosOpenNewFile() {
376✔
431
  char keepName[PATH_MAX + 20];
376✔
432
  TAOS_UNUSED(snprintf(keepName, sizeof(keepName), "%s.%d", tsLogObj.logName, tsLogObj.flag));
376✔
433

434
  tsLogObj.flag ^= 1;
376✔
435
  tsLogObj.lines = 0;
376✔
436
  char name[PATH_MAX + 20];
376✔
437
  TAOS_UNUSED(snprintf(name, sizeof(name), "%s.%d", tsLogObj.logName, tsLogObj.flag));
376✔
438

439
  TAOS_UNUSED(taosUmaskFile(0));
376✔
440

441
  TdFilePtr pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC);
376✔
442
  if (pFile == NULL) {
376✔
443
    tsLogObj.flag ^= 1;
×
444
    tsLogObj.lines = tsNumOfLogLines - 1000;
×
445
    uError("open new log file %s fail! reason:%s, reuse lastlog", name, tstrerror(terrno));
×
446
    return NULL;
×
447
  }
448

449
  TAOS_UNUSED(taosLockLogFile(pFile));
376✔
450
  if (taosLSeekFile(pFile, 0, SEEK_SET) < 0) {
376✔
451
    uWarn("failed to seek file:%s, reason:%s", name, tstrerror(terrno));
×
452
  }
453

454
  TdFilePtr pOldFile = tsLogObj.logHandle->pFile;
376✔
455
  tsLogObj.logHandle->pFile = pFile;
376✔
456
  tsLogObj.lines = 0;
376✔
457
  OldFileKeeper *oldFileKeeper = taosMemoryMalloc(sizeof(OldFileKeeper));
376✔
458
  if (oldFileKeeper == NULL) {
376✔
459
    uError("create old log keep info faild! mem is not enough.");
×
460
    return NULL;
×
461
  }
462
  oldFileKeeper->pOldFile = pOldFile;
376✔
463
  taosReserveOldLog(keepName, oldFileKeeper->keepName);
376✔
464

465
  uInfo("   new log file:%d is opened", tsLogObj.flag);
376✔
466
  uInfo("==================================");
376✔
467
  return oldFileKeeper;
376✔
468
}
469

470
static void *taosThreadToCloseOldFile(void *param) {
376✔
471
  if (!param) return NULL;
376✔
472
  OldFileKeeper *oldFileKeeper = (OldFileKeeper *)param;
376✔
473
  taosSsleep(20);
376✔
474
  taosCloseLogByFd(oldFileKeeper->pOldFile);
110✔
475
  taosMemoryFree(oldFileKeeper);
110✔
476
  atomic_store_8(&tsLogNeedRotate, 1);
110✔
477
  return NULL;
110✔
478
}
479

480
static int32_t taosOpenNewLogFile() {
376✔
481
  (void)taosThreadMutexLock(&tsLogObj.logMutex);
376✔
482

483
  if (tsLogObj.lines > tsNumOfLogLines && tsLogObj.openInProgress == 0) {
376✔
484
    tsLogObj.openInProgress = 1;
376✔
485

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

509
  (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
376✔
510

511
  return 0;
376✔
512
}
513

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

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

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

549
  TdFilePtr pOldFile = tsLogObj.slowHandle->pFile;
202✔
550
  tsLogObj.slowHandle->pFile = pFile;
202✔
551
  (void)taosCloseFile(&pOldFile);
202✔
552
  tsLogObj.timestampToday = taosGetTimestampToday(TSDB_TIME_PRECISION_SECONDS, NULL);
202✔
553
  (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
202✔
554
}
555

556
void taosResetLog() {
266✔
557
  // force create a new log file
558
  tsLogObj.lines = tsNumOfLogLines + 10;
266✔
559

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

570
void taosLogObjSetToday(int64_t ts) { tsLogObj.timestampToday = ts; }
202✔
571

572
static bool taosCheckFileIsOpen(char *logFileName) {
4,627,346✔
573
  TdFilePtr pFile = taosOpenFile(logFileName, TD_FILE_WRITE);
4,627,346✔
574
  if (pFile == NULL) {
4,627,346✔
575
    if (lastErrorIsFileNotExist()) {
2,781,303✔
576
      return false;
2,781,303✔
577
    } else {
578
      printf("\n%s:%d failed to open log file:%s, reason:%s\n", __func__, __LINE__, logFileName, strerror(ERRNO));
×
579
      SET_ERROR_MSG("%s:%d failed to open log file:%s, reason:%s", __func__, __LINE__, logFileName, strerror(ERRNO));
×
580
      return true;
×
581
    }
582
  }
583

584
  if (taosLockLogFile(pFile)) {
1,846,043✔
585
    taosUnLockLogFile(pFile);
1,085,362✔
586
    (void)taosCloseFile(&pFile);
1,085,362✔
587
    return false;
1,085,362✔
588
  } else {
589
    (void)taosCloseFile(&pFile);
760,681✔
590
    return true;
760,681✔
591
  }
592
}
593

594
static void decideLogFileName(const char *fn, int32_t maxFileNum) {
2,919,635✔
595
  tsLogObj.fileNum = maxFileNum;
2,919,635✔
596
  if (tsLogObj.fileNum > 1) {
2,919,635✔
597
    for (int32_t i = 0; i < tsLogObj.fileNum; i++) {
2,313,673✔
598
      char fileName[PATH_MAX + 10];
2,282,370✔
599

600
      (void)snprintf(fileName, PATH_MAX + 10, "%s%d.0", fn, i);
2,313,673✔
601
      bool file1open = taosCheckFileIsOpen(fileName);
2,313,673✔
602

603
      (void)snprintf(fileName, PATH_MAX + 10, "%s%d.1", fn, i);
2,313,673✔
604
      bool file2open = taosCheckFileIsOpen(fileName);
2,313,673✔
605

606
      if (!file1open && !file2open) {
2,313,673✔
607
        (void)snprintf(tsLogObj.logName, PATH_MAX, "%s%d", fn, i);
1,552,992✔
608
        return;
1,552,992✔
609
      }
610
    }
611
  }
612

613
  if (strlen(fn) < PATH_MAX) {
1,366,643✔
614
    tstrncpy(tsLogObj.logName, fn, PATH_MAX);
1,366,643✔
615
  }
616
}
617

618
static void decideLogFileNameFlag() {
2,919,635✔
619
  char    name[PATH_MAX] = "\0";
2,919,635✔
620
  int64_t logstat0_mtime = 0;
2,919,635✔
621
  int64_t logstat1_mtime = 0;
2,919,635✔
622
  bool    log0Exist = false;
2,919,635✔
623
  bool    log1Exist = false;
2,919,635✔
624

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

633
  // if none of the log files exist, open 0, if both exists, open the old one
634
  if (!log0Exist && !log1Exist) {
2,919,635✔
635
    tsLogObj.flag = 0;
1,534,554✔
636
  } else if (!log1Exist) {
1,385,081✔
637
    tsLogObj.flag = 0;
1,384,547✔
638
  } else if (!log0Exist) {
534✔
639
    tsLogObj.flag = 1;
×
640
  } else {
641
    tsLogObj.flag = (logstat0_mtime > logstat1_mtime) ? 0 : 1;
534✔
642
  }
643
}
2,919,635✔
644

645
static void processLogFileName(const char *logName, int32_t maxFileNum) {
2,919,635✔
646
  char fullName[PATH_MAX] = {0};
2,919,635✔
647
  getFullPathName(fullName, logName);
2,919,635✔
648
  decideLogFileName(fullName, maxFileNum);
2,919,635✔
649
  decideLogFileNameFlag();
2,919,635✔
650
}
2,919,635✔
651

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

662
  processLogFileName(logName, maxFileNum);
2,919,635✔
663

664
  int32_t logNameLen = strlen(tsLogObj.logName) + 2;  // logName + ".0" or ".1"
2,919,635✔
665

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

671
  char name[PATH_MAX] = "\0";
2,919,635✔
672
  (void)snprintf(name, sizeof(name), "%s.%d", tsLogObj.logName, tsLogObj.flag);
2,919,635✔
673
  (void)taosThreadMutexInit(&tsLogObj.logMutex, NULL);
2,919,635✔
674

675
  TAOS_UNUSED(taosUmaskFile(0));
2,919,635✔
676
  tsLogObj.logHandle = taosLogBuffNew(LOG_DEFAULT_BUF_SIZE);
2,919,635✔
677
  if (tsLogObj.logHandle == NULL) return terrno;
2,919,635✔
678

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

687
  // only an estimate for number of lines
688
  int64_t filesize = 0;
2,919,635✔
689
  TAOS_CHECK_EXIT(taosFStatFile(tsLogObj.logHandle->pFile, &filesize, NULL));
2,919,635✔
690

691
  tsLogObj.lines = (int32_t)(filesize / 60);
2,919,635✔
692

693
  if (taosLSeekFile(tsLogObj.logHandle->pFile, 0, SEEK_END) < 0) {
2,919,635✔
694
    TAOS_CHECK_EXIT(terrno);
×
695
  }
696

697
  (void)snprintf(name, sizeof(name),
2,919,635✔
698
                 "==================================================\n"
699
                 "                new log file\n"
700
                 "==================================================\n");
701
  if (taosWriteFile(tsLogObj.logHandle->pFile, name, (uint32_t)strlen(name)) <= 0) {
2,919,635✔
702
    TAOS_CHECK_EXIT(terrno);
×
703
  }
704

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

714
static void taosUpdateLogNums(ELogLevel level) {
2,147,483,647✔
715
  switch (level) {
2,147,483,647✔
716
    case DEBUG_ERROR:
605,312,143✔
717
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfErrorLogs, 1));
605,312,143✔
718
      break;
605,360,593✔
719
    case DEBUG_INFO:
2,147,483,647✔
720
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfInfoLogs, 1));
2,147,483,647✔
721
      break;
2,147,483,647✔
722
    case DEBUG_DEBUG:
2,147,483,647✔
723
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfDebugLogs, 1));
2,147,483,647✔
724
      break;
2,147,483,647✔
725
    case DEBUG_DUMP:
2,147,483,647✔
726
    case DEBUG_TRACE:
727
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfTraceLogs, 1));
2,147,483,647✔
728
      break;
2,147,483,647✔
UNCOV
729
    default:
×
UNCOV
730
      break;
×
731
  }
732
}
2,147,483,647✔
733

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

738
  TAOS_UNUSED(taosGetTimeOfDay(&timeSecs));
2,147,483,647✔
739
  time_t curTime = timeSecs.tv_sec;
2,147,483,647✔
740
  ptm = taosLocalTime(&curTime, &Tm, NULL, 0, NULL);
2,147,483,647✔
741
  if (ptm == NULL) {
2,147,483,647✔
742
    uError("%s failed to get local time, code:%d", __FUNCTION__, ERRNO);
×
743
    return 0;
×
744
  }
745
  return snprintf(buffer, LOG_MAX_STACK_LINE_BUFFER_SIZE, "%02d/%02d %02d:%02d:%02d.%06d %08" PRId64 " %s %s",
2,147,483,647✔
746
                  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✔
747
                  taosGetSelfPthreadId(), LOG_EDITION_FLG, flags);
748
}
749

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

759
    if (tsNumOfLogLines > 0) {
2,147,483,647✔
760
      TAOS_UNUSED(atomic_add_fetch_32(&tsLogObj.lines, 1));
2,147,483,647✔
761
      if ((tsLogObj.lines > tsNumOfLogLines) && (tsLogObj.openInProgress == 0)) {
2,147,483,647✔
762
        TAOS_UNUSED(taosOpenNewLogFile());
110✔
763
      }
764
    }
765
  }
766

767
  int fd = 0;
2,147,483,647✔
768
  if (tsLogObj.outputType == LOG_OUTPUT_FILE) {
2,147,483,647✔
769
#ifndef TAOSD_INTEGRATED    
770
    if (dflag & DEBUG_SCREEN) fd = 1;
2,147,483,647✔
771
#else
772
    if ((dflag & DEBUG_SCREEN) && tsLogEmbedded) fd = 1;
773
#endif
774
  } else if (tsLogObj.outputType == LOG_OUTPUT_STDOUT) {
2,952,343✔
775
    fd = 1;
169,978✔
776
  } else if (tsLogObj.outputType == LOG_OUTPUT_STDERR) {
2,782,365✔
777
    fd = 2;
5,550✔
778
  }
779

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

794
/*
795
  use taosPrintLogImpl_useStackBuffer to avoid stack overflow
796

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

803
  int32_t writeLen = len + vsnprintf(buffer + len, LOG_MAX_STACK_LINE_BUFFER_SIZE - len - 1, format, args);
2,147,483,647✔
804
  if (writeLen > LOG_MAX_STACK_LINE_SIZE) {
2,147,483,647✔
805
    return 1;
289,683,045✔
806
  }
807

808
  buffer[writeLen++] = '\n';
2,147,483,647✔
809
  buffer[writeLen] = 0;
2,147,483,647✔
810

811
  taosPrintLogImp(level, dflag, buffer, writeLen);
2,147,483,647✔
812

813
  if (tsLogFp && level <= DEBUG_INFO) {
2,147,483,647✔
814
    buffer[writeLen - 1] = 0;
2,147,483,647✔
815
    (*tsLogFp)(taosGetTimestampMs(), level, buffer + len);
2,147,483,647✔
816
  }
817
  return 0;
2,147,483,647✔
818
}
819
static int8_t taosPrintLogImplUseHeapBuffer(const char *flags, int32_t level, int32_t dflag, const char *format,
289,672,057✔
820
                                            va_list args) {
821
  char *buffer = taosMemoryCalloc(1, LOG_MAX_LINE_BUFFER_SIZE + 1);
289,672,057✔
822
  if (buffer == NULL) {
289,677,716✔
823
    return 1;
×
824
  }
825
  int32_t len = taosBuildLogHead(buffer, flags);
289,677,716✔
826

827
  int32_t writeLen = len + vsnprintf(buffer + len, LOG_MAX_LINE_BUFFER_SIZE - len - 1, format, args);
289,697,483✔
828

829
  if (writeLen > LOG_MAX_LINE_SIZE) writeLen = LOG_MAX_LINE_SIZE;
289,695,991✔
830
  buffer[writeLen++] = '\n';
289,695,991✔
831
  buffer[writeLen] = 0;
289,681,249✔
832

833
  taosPrintLogImp(level, dflag, buffer, writeLen);
289,692,126✔
834

835
  if (tsLogFp && level <= DEBUG_INFO) {
289,699,455✔
836
    buffer[writeLen - 1] = 0;
26,653,755✔
837
    (*tsLogFp)(taosGetTimestampMs(), level, buffer + len);
53,307,510✔
838
  }
839
  taosMemoryFree(buffer);
289,699,455✔
840
  return 0;
289,700,230✔
841
}
842
void taosPrintLog(const char *flags, int32_t level, int32_t dflag, const char *format, ...) {
2,147,483,647✔
843
  if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return;
2,147,483,647✔
844

845
  va_list argpointer, argpointer_copy;
2,147,483,647✔
846
  va_start(argpointer, format);
2,147,483,647✔
847
  va_copy(argpointer_copy, argpointer);
2,147,483,647✔
848

849
  if (taosPrintLogImplUseStackBuffer(flags, level, dflag, format, argpointer) == 0) {
2,147,483,647✔
850
  } else {
851
    TAOS_UNUSED(taosPrintLogImplUseHeapBuffer(flags, level, dflag, format, argpointer_copy));
289,679,353✔
852
  }
853
  va_end(argpointer_copy);
2,147,483,647✔
854
  va_end(argpointer);
2,147,483,647✔
855
}
856

857
void taosPrintLongString(const char *flags, int32_t level, int32_t dflag, const char *format, ...) {
649,797,325✔
858
  if (!osLogSpaceSufficient()) return;
649,797,325✔
859
  if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return;
649,797,130✔
860

861
  char *buffer = taosMemoryMalloc(LOG_MAX_LINE_DUMP_BUFFER_SIZE);
649,797,130✔
862
  if (!buffer) return;
649,797,853✔
863
  int32_t len = taosBuildLogHead(buffer, flags);
649,797,853✔
864

865
  va_list argpointer;
646,938,545✔
866
  va_start(argpointer, format);
649,796,520✔
867
  len += vsnprintf(buffer + len, LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 - len, format, argpointer);
649,796,520✔
868
  va_end(argpointer);
649,796,260✔
869

870
  len = len > LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 ? LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 : len;
649,796,260✔
871
  buffer[len++] = '\n';
649,796,260✔
872
  buffer[len] = 0;
649,796,478✔
873

874
  taosPrintLogImp(level, dflag, buffer, len);
649,796,898✔
875
  taosMemoryFree(buffer);
649,797,853✔
876
}
877

878
void taosPrintSlowLog(const char *format, ...) {
174,533✔
879
  if (!osLogSpaceSufficient()) return;
174,533✔
880

881
  int64_t delta = taosGetTimestampSec() - tsLogObj.timestampToday;
174,533✔
882
  if (delta >= 86400 || delta < 0) {
174,533✔
883
    taosOpenNewSlowLogFile();
202✔
884
  }
885

886
  char   *buffer = taosMemoryMalloc(LOG_MAX_LINE_DUMP_BUFFER_SIZE);
174,533✔
887
  int32_t len = taosBuildLogHead(buffer, "");
174,533✔
888

889
  va_list argpointer;
173,319✔
890
  va_start(argpointer, format);
174,533✔
891
  len += vsnprintf(buffer + len, LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 - len, format, argpointer);
174,533✔
892
  va_end(argpointer);
174,533✔
893

894
  if (len < 0 || len > LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2) {
174,533✔
895
    len = LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2;
×
896
  }
897
  buffer[len++] = '\n';
174,533✔
898
  buffer[len] = 0;
174,533✔
899

900
  TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfSlowLogs, 1));
174,533✔
901

902
  if (tsAsyncLog) {
174,533✔
903
    TAOS_UNUSED(taosPushLogBuffer(tsLogObj.slowHandle, buffer, len));
434✔
904
  } else {
905
    TAOS_UNUSED(taosWriteFile(tsLogObj.slowHandle->pFile, buffer, len));
174,099✔
906
  }
907

908
  taosMemoryFree(buffer);
174,533✔
909
}
910

911
static void taosCloseLogByFd(TdFilePtr pFile) {
110✔
912
  if (pFile != NULL) {
110✔
913
    taosUnLockLogFile(pFile);
110✔
914
    (void)taosCloseFile(&pFile);
110✔
915
  }
916
}
110✔
917

918
static SLogBuff *taosLogBuffNew(int32_t bufSize) {
5,831,263✔
919
  SLogBuff *pLogBuf = NULL;
5,831,263✔
920

921
  pLogBuf = taosMemoryCalloc(1, sizeof(SLogBuff));
5,831,263✔
922
  if (pLogBuf == NULL) return NULL;
5,831,263✔
923

924
  LOG_BUF_BUFFER(pLogBuf) = taosMemoryMalloc(bufSize);
5,831,263✔
925
  if (LOG_BUF_BUFFER(pLogBuf) == NULL) goto _err;
5,831,263✔
926

927
  LOG_BUF_START(pLogBuf) = LOG_BUF_END(pLogBuf) = 0;
5,831,263✔
928
  LOG_BUF_SIZE(pLogBuf) = bufSize;
5,831,263✔
929
  pLogBuf->minBuffSize = bufSize / 10;
5,831,263✔
930
  pLogBuf->stop = 0;
5,831,263✔
931
  pLogBuf->writeInterval = LOG_DEFAULT_INTERVAL;
5,831,263✔
932
  pLogBuf->lock = 0;
5,831,263✔
933
  if (taosThreadMutexInit(&LOG_BUF_MUTEX(pLogBuf), NULL) < 0) goto _err;
5,831,263✔
934
  // tsem_init(&(pLogBuf->buffNotEmpty), 0, 0);
935

936
  return pLogBuf;
5,831,263✔
937

938
_err:
×
939
  taosMemoryFreeClear(LOG_BUF_BUFFER(pLogBuf));
×
940
  taosMemoryFreeClear(pLogBuf);
×
941
  return NULL;
×
942
}
943

944
static void taosCopyLogBuffer(SLogBuff *pLogBuf, int32_t start, int32_t end, const char *msg, int32_t msgLen) {
2,147,483,647✔
945
  if (start > end) {
2,147,483,647✔
946
    memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, msgLen);
33,466,580✔
947
  } else {
948
    if (LOG_BUF_SIZE(pLogBuf) - end < msgLen) {
2,147,483,647✔
949
      memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, LOG_BUF_SIZE(pLogBuf) - end);
9,071✔
950
      memcpy(LOG_BUF_BUFFER(pLogBuf), msg + LOG_BUF_SIZE(pLogBuf) - end, msgLen - LOG_BUF_SIZE(pLogBuf) + end);
9,071✔
951
    } else {
952
      memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, msgLen);
2,147,483,647✔
953
    }
954
  }
955
  LOG_BUF_END(pLogBuf) = (LOG_BUF_END(pLogBuf) + msgLen) % LOG_BUF_SIZE(pLogBuf);
2,147,483,647✔
956
}
2,147,483,647✔
957

958
static int32_t taosPushLogBuffer(SLogBuff *pLogBuf, const char *msg, int32_t msgLen) {
2,147,483,647✔
959
  int32_t        start = 0;
2,147,483,647✔
960
  int32_t        end = 0;
2,147,483,647✔
961
  int32_t        remainSize = 0;
2,147,483,647✔
962
  static int64_t lostLine = 0;
963
  char           tmpBuf[128];
1,472,248,184✔
964
  int32_t        tmpBufLen = 0;
2,147,483,647✔
965

966
  if (pLogBuf == NULL || pLogBuf->stop) return -1;
2,147,483,647✔
967

968
  (void)taosThreadMutexLock(&LOG_BUF_MUTEX(pLogBuf));
2,147,483,647✔
969
  start = LOG_BUF_START(pLogBuf);
2,147,483,647✔
970
  end = LOG_BUF_END(pLogBuf);
2,147,483,647✔
971

972
  remainSize = (start > end) ? (start - end - 1) : (start + LOG_BUF_SIZE(pLogBuf) - end - 1);
2,147,483,647✔
973

974
  if (lostLine > 0) {
2,147,483,647✔
975
    tmpBufLen = snprintf(tmpBuf, tListLen(tmpBuf), "...Lost %" PRId64 " lines here...\n", lostLine);
×
976
  }
977

978
  if (remainSize <= msgLen || ((lostLine > 0) && (remainSize <= (msgLen + tmpBufLen)))) {
2,147,483,647✔
979
    lostLine++;
×
980
    tsAsyncLogLostLines++;
×
981
    (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
×
982
    return -1;
×
983
  }
984

985
  if (lostLine > 0) {
2,147,483,647✔
986
    taosCopyLogBuffer(pLogBuf, start, end, tmpBuf, tmpBufLen);
×
987
    lostLine = 0;
×
988
  }
989

990
  taosCopyLogBuffer(pLogBuf, LOG_BUF_START(pLogBuf), LOG_BUF_END(pLogBuf), msg, msgLen);
2,147,483,647✔
991

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

1002
  (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
2,147,483,647✔
1003

1004
  return 0;
2,147,483,647✔
1005
}
1006

1007
static int32_t taosGetLogRemainSize(SLogBuff *pLogBuf, int32_t start, int32_t end) {
171,021,532✔
1008
  int32_t rSize = end - start;
171,021,532✔
1009

1010
  return rSize >= 0 ? rSize : LOG_BUF_SIZE(pLogBuf) + rSize;
171,021,532✔
1011
}
1012

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

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

1031
  int32_t pollSize = taosGetLogRemainSize(pLogBuf, start, end);
166,338,748✔
1032
  if (pollSize < pLogBuf->minBuffSize) {
166,338,748✔
1033
    pLogBuf->lastDuration += pLogBuf->writeInterval;
166,319,994✔
1034
    if (pLogBuf->lastDuration < LOG_MAX_WAIT_MSEC) {
166,319,994✔
1035
      return;
161,655,964✔
1036
    }
1037
  }
1038

1039
  pLogBuf->lastDuration = 0;
4,682,784✔
1040

1041
  if (start < end) {
4,682,784✔
1042
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf) + start, pollSize));
4,673,551✔
1043
  } else {
1044
    int32_t tsize = LOG_BUF_SIZE(pLogBuf) - start;
9,233✔
1045
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf) + start, tsize));
9,233✔
1046

1047
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf), end));
9,233✔
1048
  }
1049

1050
  dbgWN++;
4,682,784✔
1051
  dbgWSize += pollSize;
4,682,784✔
1052

1053
  if (pollSize < pLogBuf->minBuffSize) {
4,682,784✔
1054
    dbgSmallWN++;
4,664,030✔
1055
    if (pLogBuf->writeInterval < LOG_MAX_INTERVAL) {
4,664,030✔
1056
      pLogBuf->writeInterval += LOG_INTERVAL_STEP;
×
1057
    }
1058
  } else if (pollSize > LOG_BUF_SIZE(pLogBuf) / 3) {
18,754✔
1059
    dbgBigWN++;
×
1060
    pLogBuf->writeInterval = LOG_MIN_INTERVAL;
×
1061
  } else if (pollSize > LOG_BUF_SIZE(pLogBuf) / 4) {
18,754✔
1062
    if (pLogBuf->writeInterval > LOG_MIN_INTERVAL) {
×
1063
      pLogBuf->writeInterval -= LOG_INTERVAL_STEP;
×
1064
    }
1065
  }
1066

1067
  (void)taosThreadMutexLock(&LOG_BUF_MUTEX(pLogBuf));
4,682,784✔
1068
  LOG_BUF_START(pLogBuf) = (LOG_BUF_START(pLogBuf) + pollSize) % LOG_BUF_SIZE(pLogBuf);
4,682,784✔
1069

1070
  start = LOG_BUF_START(pLogBuf);
4,682,784✔
1071
  end = LOG_BUF_END(pLogBuf);
4,682,784✔
1072
  (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
4,682,784✔
1073

1074
  pollSize = taosGetLogRemainSize(pLogBuf, start, end);
4,682,784✔
1075
  if (pollSize < pLogBuf->minBuffSize) {
4,682,784✔
1076
    return;
4,682,784✔
1077
  }
1078

1079
  pLogBuf->writeInterval = 0;
×
1080
}
1081

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

1114
  // compress or remove the old log files
1115
  TdDirPtr pDir = taosOpenDir(tsLogDir);
1,848,431✔
1116
  if (!pDir) goto _exit;
1,848,431✔
1117
  TdDirEntryPtr de = NULL;
1,846,435✔
1118
  while ((de = taosReadDir(pDir))) {
11,241,819✔
1119
    if (taosDirEntryIsDir(de)) {
9,395,384✔
1120
      continue;
3,795,666✔
1121
    }
1122
    char *fname = taosGetDirEntryName(de);
5,702,304✔
1123
    if (!fname) {
5,702,304✔
1124
      continue;
×
1125
    }
1126

1127
    if (!strstr(fname, filePrefix)) continue;
5,702,304✔
1128

1129
    char *pSec = strrchr(fname, '.');
2,104,858✔
1130
    if (!pSec) {
2,104,858✔
1131
      continue;
×
1132
    }
1133
    char *pIter = pSec;
2,104,858✔
1134
    bool  isSec = true;
2,104,858✔
1135
    while (*(++pIter)) {
4,209,611✔
1136
      if (!isdigit(*pIter)) {
2,104,858✔
1137
        isSec = false;
105✔
1138
        break;
105✔
1139
      }
1140
    }
1141
    if (!isSec) {
2,104,858✔
1142
      continue;
105✔
1143
    }
1144

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

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

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

1163
    int64_t inactiveSec = taosGetTimestampMs() / 1000 - mtime;
×
1164

1165
    if (inactiveSec < LOG_INACTIVE_TIME) {
×
1166
      continue;
×
1167
    }
1168

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

1181
  if (tsLogKeepDays != 0) {
1,846,435✔
1182
    taosRemoveOldFiles(tsLogDir, abs(tsLogKeepDays));
481✔
1183
  }
1184
_exit:
1,848,326✔
1185
  atomic_store_8(&tsLogRotateRunning, 0);
1,848,431✔
1186
  taosMemFreeClear(filePrefix);
1,848,431✔
1187
  return NULL;
1,848,431✔
1188
}
1189

1190
static void *taosAsyncOutputLog(void *param) {
2,919,635✔
1191
  SLogBuff *pLogBuf = (SLogBuff *)tsLogObj.logHandle;
2,919,635✔
1192
  SLogBuff *pSlowBuf = (SLogBuff *)tsLogObj.slowHandle;
2,919,635✔
1193

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

1200
  while (1) {
2,147,483,647✔
1201
    if (pSlowBuf) {
2,147,483,647✔
1202
      writeInterval = TMIN(pLogBuf->writeInterval, pSlowBuf->writeInterval);
2,147,483,647✔
1203
    } else {
1204
      writeInterval = pLogBuf->writeInterval;
2,877,797✔
1205
    }
1206
    count += writeInterval;
2,147,483,647✔
1207
    updateCron++;
2,147,483,647✔
1208
    taosMsleep(writeInterval);
2,147,483,647✔
1209
    if (count > 1000) {
2,147,483,647✔
1210
      TAOS_UNUSED(osUpdate());
152,698,396✔
1211
      count = 0;
152,698,396✔
1212
    }
1213

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

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

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

1251
  return NULL;
2,918,286✔
1252
}
1253

1254
bool taosAssertDebug(bool condition, const char *file, int32_t line, bool core, const char *format, ...) {
404✔
1255
  if (condition) return false;
404✔
1256

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

1263
  va_list argpointer;
×
1264
  va_start(argpointer, format);
202✔
1265
  len = len + vsnprintf(buffer + len, LOG_MAX_LINE_BUFFER_SIZE - len, format, argpointer);
202✔
1266
  va_end(argpointer);
202✔
1267
  buffer[len++] = '\n';
202✔
1268
  buffer[len] = 0;
202✔
1269
  taosPrintLogImp(1, 255, buffer, len);
202✔
1270

1271
  taosPrintLog(flags, level, dflag, "tAssert at file %s:%d exit:%d", file, line, tsAssert);
202✔
1272
#ifndef TD_ASTRA
1273
  taosPrintTrace(flags, level, dflag, -1);
3,434✔
1274
#endif
1275
  if (tsAssert || core) {
202✔
1276
    taosCloseLog();
×
1277
    taosMsleep(300);
×
1278

1279
#ifdef NDEBUG
1280
    abort();
1281
#else
1282
    assert(0);
×
1283
#endif
1284
  }
1285

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

1296
  if (pMsg && msgLen > 0) {
404✔
1297
    snprintf(filepath, sizeof(filepath), "%s%s.%sCrashLog", tsLogDir, TD_DIRSEP, nodeType);
202✔
1298

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

1305
    if (taosLockFile(pFile) < 0) {
202✔
1306
      taosPrintLog(flags, level, dflag, "failed to lock file:%s since %s", filepath, terrstr());
×
1307
      goto _return;
×
1308
    }
1309

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

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

1326
    TAOS_UNUSED(taosUnLockFile(pFile));
202✔
1327
  }
1328

1329
_return:
202✔
1330

1331
  if (pFile) (void)taosCloseFile(&pFile);
404✔
1332

1333
  taosPrintLog(flags, level, dflag, "crash signal is %d", signum);
404✔
1334

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

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

1368
crashBasicInfo gCrashBasicInfo = {0};
1369

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

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

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

1424
void checkAndPrepareCrashInfo() {
202✔
1425
  return checkWriteCrashLogToFileInNewThead();
202✔
1426
}
1427

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

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

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

1461
  if (NULL == *pFd) {
404✔
1462
    int64_t filesize = 0;
404✔
1463
    if (taosStatFile(filepath, &filesize, NULL, NULL) < 0) {
404✔
1464
      if (TAOS_SYSTEM_ERROR(ENOENT) == terrno) {
×
1465
        return;
×
1466
      }
1467

1468
      taosPrintLog(flags, level, dflag, "failed to stat file:%s since %s", filepath, terrstr());
×
1469
      return;
×
1470
    }
1471

1472
    if (filesize <= 0) {
404✔
1473
      return;
×
1474
    }
1475

1476
    pFile = taosOpenFile(filepath, TD_FILE_READ | TD_FILE_WRITE);
404✔
1477
    if (pFile == NULL) {
404✔
1478
      if (errorIsFileNotExist(terrno)) {
×
1479
        return;
×
1480
      }
1481

1482
      taosPrintLog(flags, level, dflag, "failed to open file:%s since %s", filepath, terrstr());
×
1483
      return;
×
1484
    }
1485

1486
    TAOS_UNUSED(taosLockFile(pFile));
404✔
1487
  } else {
1488
    pFile = *pFd;
×
1489
  }
1490

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

1502
  buf = taosMemoryMalloc(msgLen);
404✔
1503
  if (NULL == buf) {
404✔
1504
    taosPrintLog(flags, level, dflag, "failed to malloc buf, size:%" PRId64, msgLen);
×
1505
    goto _return;
×
1506
  }
1507

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

1516
  *pMsg = buf;
202✔
1517
  *pMsgLen = msgLen;
202✔
1518
  *pFd = pFile;
202✔
1519

1520
  return;
202✔
1521

1522
_return:
202✔
1523

1524
  if (truncateFile) {
202✔
1525
    TAOS_UNUSED(taosFtruncateFile(pFile, 0));
202✔
1526
  }
1527
  TAOS_UNUSED(taosUnLockFile(pFile));
202✔
1528
  TAOS_UNUSED(taosCloseFile(&pFile));
202✔
1529
  taosMemoryFree(buf);
202✔
1530

1531
  *pMsg = NULL;
202✔
1532
  *pMsgLen = 0;
202✔
1533
  *pFd = NULL;
202✔
1534
}
1535

1536
void taosReleaseCrashLogFile(TdFilePtr pFile, bool truncateFile) {
202✔
1537
  if (truncateFile) {
202✔
1538
    TAOS_UNUSED(taosFtruncateFile(pFile, 0));
202✔
1539
  }
1540

1541
  TAOS_UNUSED(taosUnLockFile(pFile));
202✔
1542
  TAOS_UNUSED(taosCloseFile(&pFile));
202✔
1543
}
202✔
1544
#endif // USE_REPORT
1545

1546
#ifdef NDEBUG
1547
bool taosAssertRelease(bool condition) {
1548
  if (condition) return false;
1549

1550
  const char *flags = "UTL FATAL ";
1551
  ELogLevel   level = DEBUG_FATAL;
1552
  int32_t     dflag = 255;  // tsLogEmbedded ? 255 : uDebugFlag
1553

1554
  taosPrintLog(flags, level, dflag, "tAssert called in release mode, exit:%d", tsAssert);
1555
  taosPrintTrace(flags, level, dflag, 0);
1556

1557
  if (tsAssert) {
1558
    taosMsleep(300);
1559
    abort();
1560
  }
1561

1562
  return true;
1563
}
1564
#endif
1565

1566
#define NUM_BASE 100
1567
#define DIGIT_LENGTH 2
1568
#define MAX_DIGITS 24
1569

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

1576
  char  temp[MAX_DIGITS];
2,147,483,647✔
1577
  char* p = temp + tListLen(temp);
2,147,483,647✔
1578

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

1587
  // Process the remaining 1 or 2 digits
1588
  if (val >= 10) {
2,147,483,647✔
1589
    // If the number is 10 or more, get the 2 digits from the look-up table
1590
    p -= DIGIT_LENGTH;
1,887,861,331✔
1591
    TAOS_STRNCPY(p, lut + val * DIGIT_LENGTH, DIGIT_LENGTH);
1,887,874,885✔
1592
  } else if (val > 0 || p == temp) {
1,834,745,582✔
1593
    // If the number is less than 10, add the single digit to the buffer
1594
    p -= 1;
1,834,745,380✔
1595
    *p = val + '0';
1,837,183,594✔
1596
  }
1597

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

1607
  return buf + len;
2,147,483,647✔
1608
}
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