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

taosdata / TDengine / #4720

08 Sep 2025 08:43AM UTC coverage: 58.139% (-0.6%) from 58.762%
#4720

push

travis-ci

web-flow
Merge pull request #32881 from taosdata/enh/add-new-windows-ci

fix(ci): update workflow reference to use new Windows CI YAML

133181 of 292179 branches covered (45.58%)

Branch coverage included in aggregate %.

201691 of 283811 relevant lines covered (71.07%)

5442780.71 hits per line

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

66.3
/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 simDebugFlag = 131;
144
int32_t bseDebugFlag = 131;
145

146
int32_t tqClientDebugFlag = 131;
147

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

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

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

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

188
static void getFullPathName(char *fullName, const char *logName) {
13,699✔
189
  if (strlen(tsLogDir) != 0) {
13,699!
190
    char lastC = tsLogDir[strlen(tsLogDir) - 1];
13,699✔
191
    if (lastC == '\\' || lastC == '/') {
13,699!
192
      snprintf(fullName, PATH_MAX,
3,610✔
193
               "%s"
194
               "%s",
195
               tsLogDir, logName);
196
    } else {
197
      snprintf(fullName, PATH_MAX, "%s" TD_DIRSEP "%s", tsLogDir, logName);
10,089✔
198
    }
199
  } else {
200
    snprintf(fullName, PATH_MAX, "%s", logName);
×
201
  }
202
}
13,699✔
203

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

212
  getFullPathName(tsLogObj.slowLogName, logFileName);
6,821✔
213

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

223
  tsLogObj.timestampToday = taosGetTimestampToday(TSDB_TIME_PRECISION_SECONDS, NULL);
6,821✔
224
  tsLogObj.slowHandle = taosLogBuffNew(LOG_SLOW_BUF_SIZE);
6,821✔
225
  if (tsLogObj.slowHandle == NULL) return terrno;
6,821!
226

227
  TAOS_UNUSED(taosUmaskFile(0));
6,821✔
228
  tsLogObj.slowHandle->pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_READ | TD_FILE_WRITE | TD_FILE_APPEND);
6,821✔
229
  if (tsLogObj.slowHandle->pFile == NULL) {
6,821!
230
    (void)printf("\nfailed to open slow log file:%s, reason:%s\n", name, strerror(ERRNO));
×
231
    return terrno;
×
232
  }
233

234
  return 0;
6,821✔
235
}
236

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

270
    if ((p = strrchr(pLog, '/')) || (p = strrchr(pLog, '\\'))) {
12!
271
      pLogName = p + 1;
6✔
272
    } else {
273
      pLogName = pLog;
6✔
274
    }
275
    if (strcmp(pLogName, ".") == 0 || strcmp(pLogName, "..") == 0) {
12✔
276
      fprintf(stderr, "invalid log output destination:%s\n", pLog);
6✔
277
      return TSDB_CODE_INVALID_CFG;
6✔
278
    }
279

280
    if (!tIsValidFileName(pLogName, NULL)) {
6!
281
      fprintf(stderr, "invalid log output destination:%s, contains illegal char\n", pLog);
×
282
      return TSDB_CODE_INVALID_CFG;
×
283
    }
284
    if (ppLogName) *ppLogName = pLogName;
6!
285
  }
286
  return 0;
6,823✔
287
}
288

289
int32_t taosInitLog(const char *logName, int32_t maxFiles, bool tsc) {
7,124✔
290
  if (atomic_val_compare_exchange_8(&tsLogInited, 0, 1) != 0) return 0;
7,124✔
291
  int32_t code = osUpdate();
6,878✔
292
  if (code != 0) {
6,878!
293
    uError("failed to update os info, reason:%s", tstrerror(code));
×
294
  }
295

296
  if (tsLogObj.outputType == LOG_OUTPUT_STDOUT || tsLogObj.outputType == LOG_OUTPUT_STDERR ||
6,878!
297
      tsLogObj.outputType == LOG_OUTPUT_NULL) {
6,878!
298
    return 0;
×
299
  }
300

301
  TAOS_CHECK_RETURN(taosInitNormalLog(logName, maxFiles));
6,878!
302
  if (tsc) {
6,878✔
303
    TAOS_CHECK_RETURN(taosInitSlowLog());
6,821!
304
  }
305
  TAOS_CHECK_RETURN(taosStartLog());
6,878!
306
  return 0;
6,878✔
307
}
308

309
void taosSetNoNewFile() { tsLogObj.openInProgress = 1; }
3✔
310

311
static void taosStopLog() {
6,859✔
312
  if (tsLogObj.logHandle) {
6,859✔
313
    tsLogObj.logHandle->stop = 1;
6,857✔
314
  }
315
  if (tsLogObj.slowHandle) {
6,859✔
316
    tsLogObj.slowHandle->stop = 1;
6,821✔
317
  }
318
}
6,859✔
319

320
void taosCloseLog() {
6,859✔
321
  taosStopLog();
6,859✔
322

323
  if (tsLogObj.logHandle != NULL && taosCheckPthreadValid(tsLogObj.logHandle->asyncThread)) {
6,859!
324
    (void)taosThreadJoin(tsLogObj.logHandle->asyncThread, NULL);
6,857✔
325
    taosThreadClear(&tsLogObj.logHandle->asyncThread);
6,857✔
326
  }
327

328
  if (tsLogObj.slowHandle != NULL) {
6,859✔
329
    (void)taosThreadMutexDestroy(&tsLogObj.slowHandle->buffMutex);
6,821✔
330
    (void)taosCloseFile(&tsLogObj.slowHandle->pFile);
6,821✔
331
    taosMemoryFreeClear(tsLogObj.slowHandle->buffer);
6,821!
332
    taosMemoryFreeClear(tsLogObj.slowHandle);
6,821!
333
  }
334

335
  if (tsLogObj.logHandle != NULL) {
6,859✔
336
    tsLogInited = 0;
6,857✔
337

338
    (void)taosThreadMutexDestroy(&tsLogObj.logHandle->buffMutex);
6,857✔
339
    (void)taosCloseFile(&tsLogObj.logHandle->pFile);
6,857✔
340
    taosMemoryFreeClear(tsLogObj.logHandle->buffer);
6,857!
341
    (void)taosThreadMutexDestroy(&tsLogObj.logMutex);
6,857✔
342
    taosMemoryFreeClear(tsLogObj.logHandle);
6,857!
343
    tsLogObj.logHandle = NULL;
6,857✔
344
  }
345
  taosMemoryFreeClear(tsLogOutput);
6,859!
346
}
6,859✔
347

348
static bool taosLockLogFile(TdFilePtr pFile) {
10,900✔
349
  if (pFile == NULL) return false;
10,900!
350

351
  if (tsLogObj.fileNum > 1) {
10,900✔
352
    int32_t ret = taosLockFile(pFile);
6,072✔
353
    if (ret == 0) {
6,072✔
354
      return true;
5,771✔
355
    }
356
  }
357

358
  return false;
5,129✔
359
}
360

361
static void taosUnLockLogFile(TdFilePtr pFile) {
3,725✔
362
  if (pFile == NULL) return;
3,725!
363

364
  if (tsLogObj.fileNum > 1) {
3,725✔
365
    int32_t code = taosUnLockFile(pFile);
3,724✔
366
    if (code != 0) {
3,724!
367
      TAOS_UNUSED(printf("failed to unlock log file:%p, reason:%s\n", pFile, tstrerror(code)));
×
368
    }
369
  }
370
}
371

372
static void taosReserveOldLog(char *oldName, char *keepName) {
4✔
373
  if (tsLogKeepDays == 0) {
4!
374
    keepName[0] = 0;
4✔
375
    return;
4✔
376
  }
377

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

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

423
  tsLogObj.flag ^= 1;
4✔
424
  tsLogObj.lines = 0;
4✔
425
  char name[PATH_MAX + 20];
426
  TAOS_UNUSED(snprintf(name, sizeof(name), "%s.%d", tsLogObj.logName, tsLogObj.flag));
4✔
427

428
  TAOS_UNUSED(taosUmaskFile(0));
4✔
429

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

438
  TAOS_UNUSED(taosLockLogFile(pFile));
4✔
439
  if (taosLSeekFile(pFile, 0, SEEK_SET) < 0) {
4!
440
    uWarn("failed to seek file:%s, reason:%s", name, tstrerror(terrno));
×
441
  }
442

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

454
  uInfo("   new log file:%d is opened", tsLogObj.flag);
4!
455
  uInfo("==================================");
4!
456
  return oldFileKeeper;
4✔
457
}
458

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

474
static int32_t taosOpenNewLogFile() {
4✔
475
  (void)taosThreadMutexLock(&tsLogObj.logMutex);
4✔
476

477
  if (tsLogObj.lines > tsNumOfLogLines && tsLogObj.openInProgress == 0) {
4!
478
    tsLogObj.openInProgress = 1;
4✔
479

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

503
  (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
4✔
504

505
  return 0;
4✔
506
}
507

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

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

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

543
  TdFilePtr pOldFile = tsLogObj.slowHandle->pFile;
3✔
544
  tsLogObj.slowHandle->pFile = pFile;
3✔
545
  (void)taosCloseFile(&pOldFile);
3✔
546
  tsLogObj.timestampToday = taosGetTimestampToday(TSDB_TIME_PRECISION_SECONDS, NULL);
3✔
547
  (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
3✔
548
}
549

550
void taosResetLog() {
3✔
551
  // force create a new log file
552
  tsLogObj.lines = tsNumOfLogLines + 10;
3✔
553

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

564
void taosLogObjSetToday(int64_t ts) { tsLogObj.timestampToday = ts; }
3✔
565

566
static bool taosCheckFileIsOpen(char *logFileName) {
4,694✔
567
  TdFilePtr pFile = taosOpenFile(logFileName, TD_FILE_WRITE);
4,694✔
568
  if (pFile == NULL) {
4,694✔
569
    if (lastErrorIsFileNotExist()) {
676!
570
      return false;
676✔
571
    } else {
572
      printf("\n%s:%d failed to open log file:%s, reason:%s\n", __func__, __LINE__, logFileName, strerror(ERRNO));
×
573
      return true;
×
574
    }
575
  }
576

577
  if (taosLockLogFile(pFile)) {
4,018✔
578
    taosUnLockLogFile(pFile);
3,724✔
579
    (void)taosCloseFile(&pFile);
3,724✔
580
    return false;
3,724✔
581
  } else {
582
    (void)taosCloseFile(&pFile);
294✔
583
    return true;
294✔
584
  }
585
}
586

587
static void decideLogFileName(const char *fn, int32_t maxFileNum) {
6,878✔
588
  tsLogObj.fileNum = maxFileNum;
6,878✔
589
  if (tsLogObj.fileNum > 1) {
6,878✔
590
    for (int32_t i = 0; i < tsLogObj.fileNum; i++) {
2,347!
591
      char fileName[PATH_MAX + 10];
592

593
      (void)snprintf(fileName, PATH_MAX + 10, "%s%d.0", fn, i);
2,347✔
594
      bool file1open = taosCheckFileIsOpen(fileName);
2,347✔
595

596
      (void)snprintf(fileName, PATH_MAX + 10, "%s%d.1", fn, i);
2,347✔
597
      bool file2open = taosCheckFileIsOpen(fileName);
2,347✔
598

599
      if (!file1open && !file2open) {
2,347!
600
        (void)snprintf(tsLogObj.logName, PATH_MAX, "%s%d", fn, i);
2,053✔
601
        return;
2,053✔
602
      }
603
    }
604
  }
605

606
  if (strlen(fn) < PATH_MAX) {
4,825!
607
    tstrncpy(tsLogObj.logName, fn, PATH_MAX);
4,825✔
608
  }
609
}
610

611
static void decideLogFileNameFlag() {
6,878✔
612
  char    name[PATH_MAX] = "\0";
6,878✔
613
  int64_t logstat0_mtime = 0;
6,878✔
614
  int64_t logstat1_mtime = 0;
6,878✔
615
  bool    log0Exist = false;
6,878✔
616
  bool    log1Exist = false;
6,878✔
617

618
  int32_t logNameLen = strlen(tsLogObj.logName) + 2;
6,878✔
619
  if (logNameLen < PATH_MAX) {
6,878!
620
    TAOS_UNUSED(snprintf(name, PATH_MAX, "%s%s", tsLogObj.logName, ".0"));
6,878✔
621
    log0Exist = taosStatFile(name, NULL, &logstat0_mtime, NULL) == 0;
6,878✔
622
    name[logNameLen - 1] = '1';
6,878✔
623
    log1Exist = taosStatFile(name, NULL, &logstat1_mtime, NULL) == 0;
6,878✔
624
  }
625

626
  // if none of the log files exist, open 0, if both exists, open the old one
627
  if (!log0Exist && !log1Exist) {
6,878!
628
    tsLogObj.flag = 0;
4,000✔
629
  } else if (!log1Exist) {
2,878✔
630
    tsLogObj.flag = 0;
1,150✔
631
  } else if (!log0Exist) {
1,728!
632
    tsLogObj.flag = 1;
×
633
  } else {
634
    tsLogObj.flag = (logstat0_mtime > logstat1_mtime) ? 0 : 1;
1,728✔
635
  }
636
}
6,878✔
637

638
static void processLogFileName(const char *logName, int32_t maxFileNum) {
6,878✔
639
  char fullName[PATH_MAX] = {0};
6,878✔
640
  getFullPathName(fullName, logName);
6,878✔
641
  decideLogFileName(fullName, maxFileNum);
6,878✔
642
  decideLogFileNameFlag();
6,878✔
643
}
6,878✔
644

645
static int32_t taosInitNormalLog(const char *logName, int32_t maxFileNum) {
6,878✔
646
  int32_t code = 0, lino = 0;
6,878✔
647
#ifdef WINDOWS_STASH
648
  /*
649
   * always set maxFileNum to 1
650
   * means client log filename is unique in windows
651
   */
652
  maxFileNum = 1;
653
#endif
654

655
  processLogFileName(logName, maxFileNum);
6,878✔
656

657
  int32_t logNameLen = strlen(tsLogObj.logName) + 2;  // logName + ".0" or ".1"
6,878✔
658

659
  if (logNameLen < 0 || logNameLen >= PATH_MAX) {
6,878!
660
    uError("log name:%s is invalid since length:%d is out of range", logName, logNameLen);
×
661
    return TSDB_CODE_INVALID_CFG;
×
662
  }
663

664
  char name[PATH_MAX] = "\0";
6,878✔
665
  (void)snprintf(name, sizeof(name), "%s.%d", tsLogObj.logName, tsLogObj.flag);
6,878✔
666
  (void)taosThreadMutexInit(&tsLogObj.logMutex, NULL);
6,878✔
667

668
  TAOS_UNUSED(taosUmaskFile(0));
6,878✔
669
  tsLogObj.logHandle = taosLogBuffNew(LOG_DEFAULT_BUF_SIZE);
6,878✔
670
  if (tsLogObj.logHandle == NULL) return terrno;
6,878!
671

672
  tsLogObj.logHandle->pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_READ | TD_FILE_WRITE);
6,878✔
673
  if (tsLogObj.logHandle->pFile == NULL) {
6,878!
674
    (void)printf("\n%s:%d failed to open log file:%s, reason:%s\n", __func__, __LINE__, name, strerror(ERRNO));
×
675
    return terrno;
×
676
  }
677
  TAOS_UNUSED(taosLockLogFile(tsLogObj.logHandle->pFile));
6,878✔
678

679
  // only an estimate for number of lines
680
  int64_t filesize = 0;
6,878✔
681
  TAOS_CHECK_EXIT(taosFStatFile(tsLogObj.logHandle->pFile, &filesize, NULL));
6,878!
682

683
  tsLogObj.lines = (int32_t)(filesize / 60);
6,878✔
684

685
  if (taosLSeekFile(tsLogObj.logHandle->pFile, 0, SEEK_END) < 0) {
6,878!
686
    TAOS_CHECK_EXIT(terrno);
×
687
  }
688

689
  (void)snprintf(name, sizeof(name),
6,878✔
690
                 "==================================================\n"
691
                 "                new log file\n"
692
                 "==================================================\n");
693
  if (taosWriteFile(tsLogObj.logHandle->pFile, name, (uint32_t)strlen(name)) <= 0) {
6,878!
694
    TAOS_CHECK_EXIT(terrno);
×
695
  }
696

697
_exit:
6,878✔
698
  if (code != 0) {
6,878!
699
    taosUnLockLogFile(tsLogObj.logHandle->pFile);
×
700
    TAOS_UNUSED(printf("failed to init normal log file:%s at line %d, reason:%s\n", name, lino, tstrerror(code)));
×
701
  }
702
  return code;
6,878✔
703
}
704

705
static void taosUpdateLogNums(ELogLevel level) {
242,050,903✔
706
  switch (level) {
242,050,903!
707
    case DEBUG_ERROR:
220,440✔
708
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfErrorLogs, 1));
220,440✔
709
      break;
220,485✔
710
    case DEBUG_INFO:
12,667,310✔
711
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfInfoLogs, 1));
12,667,310✔
712
      break;
12,676,671✔
713
    case DEBUG_DEBUG:
213,606,280✔
714
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfDebugLogs, 1));
213,606,280✔
715
      break;
213,723,329✔
716
    case DEBUG_DUMP:
15,569,460✔
717
    case DEBUG_TRACE:
718
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfTraceLogs, 1));
15,569,460✔
719
      break;
15,569,899✔
720
    default:
×
721
      break;
×
722
  }
723
}
242,177,797✔
724

725
static inline int32_t taosBuildLogHead(char *buffer, const char *flags) {
244,186,790✔
726
  struct tm      Tm, *ptm;
727
  struct timeval timeSecs;
728

729
  TAOS_UNUSED(taosGetTimeOfDay(&timeSecs));
244,186,790✔
730
  time_t curTime = timeSecs.tv_sec;
244,131,302✔
731
  ptm = taosLocalTime(&curTime, &Tm, NULL, 0, NULL);
244,131,302✔
732
  if (ptm == NULL) {
244,049,318!
733
    uError("%s failed to get local time, code:%d", __FUNCTION__, ERRNO);
×
734
    return 0;
×
735
  }
736
  return snprintf(buffer, LOG_MAX_STACK_LINE_BUFFER_SIZE, "%02d/%02d %02d:%02d:%02d.%06d %08" PRId64 " %s %s",
244,049,318✔
737
                  ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int32_t)timeSecs.tv_usec,
244,028,799✔
738
                  taosGetSelfPthreadId(), LOG_EDITION_FLG, flags);
739
}
740

741
static inline void taosPrintLogImp(ELogLevel level, int32_t dflag, const char *buffer, int32_t len) {
243,327,233✔
742
  if ((dflag & DEBUG_FILE) && tsLogObj.logHandle && tsLogObj.logHandle->pFile != NULL && osLogSpaceSufficient()) {
243,327,233!
743
    taosUpdateLogNums(level);
242,070,408✔
744
    if (tsAsyncLog) {
242,180,878✔
745
      TAOS_UNUSED(taosPushLogBuffer(tsLogObj.logHandle, buffer, len));
950,949✔
746
    } else {
747
      TAOS_UNUSED(taosWriteFile(tsLogObj.logHandle->pFile, buffer, len));
241,229,929✔
748
    }
749

750
    if (tsNumOfLogLines > 0) {
242,268,445!
751
      TAOS_UNUSED(atomic_add_fetch_32(&tsLogObj.lines, 1));
242,269,338✔
752
      if ((tsLogObj.lines > tsNumOfLogLines) && (tsLogObj.openInProgress == 0)) {
242,272,724✔
753
        TAOS_UNUSED(taosOpenNewLogFile());
1✔
754
      }
755
    }
756
  }
757

758
  int fd = 0;
243,535,967✔
759
  if (tsLogObj.outputType == LOG_OUTPUT_FILE) {
243,535,967✔
760
#ifndef TAOSD_INTEGRATED    
761
    if (dflag & DEBUG_SCREEN) fd = 1;
243,535,901✔
762
#else
763
    if ((dflag & DEBUG_SCREEN) && tsLogEmbedded) fd = 1;
764
#endif
765
  } else if (tsLogObj.outputType == LOG_OUTPUT_STDOUT) {
66!
766
    fd = 1;
×
767
  } else if (tsLogObj.outputType == LOG_OUTPUT_STDERR) {
66!
768
    fd = 2;
×
769
  }
770

771
  if (fd) {
243,535,967✔
772
#pragma GCC diagnostic push
773
#pragma GCC diagnostic ignored "-Wunused-result"
774
#ifndef TD_ASTRA
775
    if (write(fd, buffer, (uint32_t)len) < 0) {
12,870,246✔
776
      TAOS_UNUSED(printf("failed to write log to screen, reason:%s\n", strerror(ERRNO)));
1,151,101✔
777
    }
778
#else
779
    TAOS_UNUSED(fprintf(fd == 1 ? stdout : stderr, "%s", buffer));
780
#endif
781
#pragma GCC diagnostic pop
782
  }
783
}
243,535,999✔
784

785
/*
786
  use taosPrintLogImpl_useStackBuffer to avoid stack overflow
787

788
*/
789
static int8_t taosPrintLogImplUseStackBuffer(const char *flags, int32_t level, int32_t dflag, const char *format,
243,426,421✔
790
                                             va_list args) {
791
  char    buffer[LOG_MAX_STACK_LINE_BUFFER_SIZE];
792
  int32_t len = taosBuildLogHead(buffer, flags);
243,426,421✔
793

794
  int32_t writeLen = len + vsnprintf(buffer + len, LOG_MAX_STACK_LINE_BUFFER_SIZE - len - 1, format, args);
243,365,414✔
795
  if (writeLen > LOG_MAX_STACK_LINE_SIZE) {
243,365,414✔
796
    return 1;
790,868✔
797
  }
798

799
  buffer[writeLen++] = '\n';
242,574,546✔
800
  buffer[writeLen] = 0;
242,574,546✔
801

802
  taosPrintLogImp(level, dflag, buffer, writeLen);
242,574,546✔
803

804
  if (tsLogFp && level <= DEBUG_INFO) {
242,732,210✔
805
    buffer[writeLen - 1] = 0;
10,342,674✔
806
    (*tsLogFp)(taosGetTimestampMs(), level, buffer + len);
20,685,345✔
807
  }
808
  return 0;
242,732,881✔
809
}
810
static int8_t taosPrintLogImplUseHeapBuffer(const char *flags, int32_t level, int32_t dflag, const char *format,
790,786✔
811
                                            va_list args) {
812
  char *buffer = taosMemoryCalloc(1, LOG_MAX_LINE_BUFFER_SIZE + 1);
790,786!
813
  if (buffer == NULL) {
790,785!
814
    return 1;
×
815
  }
816
  int32_t len = taosBuildLogHead(buffer, flags);
790,785✔
817

818
  int32_t writeLen = len + vsnprintf(buffer + len, LOG_MAX_LINE_BUFFER_SIZE - len - 1, format, args);
791,093✔
819

820
  if (writeLen > LOG_MAX_LINE_SIZE) writeLen = LOG_MAX_LINE_SIZE;
791,093✔
821
  buffer[writeLen++] = '\n';
791,093✔
822
  buffer[writeLen] = 0;
791,093✔
823

824
  taosPrintLogImp(level, dflag, buffer, writeLen);
791,093✔
825

826
  if (tsLogFp && level <= DEBUG_INFO) {
791,210✔
827
    buffer[writeLen - 1] = 0;
70,561✔
828
    (*tsLogFp)(taosGetTimestampMs(), level, buffer + len);
141,123✔
829
  }
830
  taosMemoryFree(buffer);
791,211!
831
  return 0;
791,209✔
832
}
833
void taosPrintLog(const char *flags, int32_t level, int32_t dflag, const char *format, ...) {
243,312,312✔
834
  if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return;
243,312,312!
835

836
  va_list argpointer, argpointer_copy;
837
  va_start(argpointer, format);
243,312,312✔
838
  va_copy(argpointer_copy, argpointer);
243,312,312✔
839

840
  if (taosPrintLogImplUseStackBuffer(flags, level, dflag, format, argpointer) == 0) {
243,312,312✔
841
  } else {
842
    TAOS_UNUSED(taosPrintLogImplUseHeapBuffer(flags, level, dflag, format, argpointer_copy));
790,702✔
843
  }
844
  va_end(argpointer_copy);
243,522,444✔
845
  va_end(argpointer);
243,522,444✔
846
}
847

848
void taosPrintLongString(const char *flags, int32_t level, int32_t dflag, const char *format, ...) {
11,798✔
849
  if (!osLogSpaceSufficient()) return;
11,798!
850
  if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return;
11,798!
851

852
  char *buffer = taosMemoryMalloc(LOG_MAX_LINE_DUMP_BUFFER_SIZE);
11,798!
853
  if (!buffer) return;
11,798!
854
  int32_t len = taosBuildLogHead(buffer, flags);
11,798✔
855

856
  va_list argpointer;
857
  va_start(argpointer, format);
11,798✔
858
  len += vsnprintf(buffer + len, LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 - len, format, argpointer);
11,798✔
859
  va_end(argpointer);
11,798✔
860

861
  len = len > LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 ? LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 : len;
11,798✔
862
  buffer[len++] = '\n';
11,798✔
863
  buffer[len] = 0;
11,798✔
864

865
  taosPrintLogImp(level, dflag, buffer, len);
11,798✔
866
  taosMemoryFree(buffer);
11,798!
867
}
868

869
void taosPrintSlowLog(const char *format, ...) {
3✔
870
  if (!osLogSpaceSufficient()) return;
3!
871

872
  int64_t delta = taosGetTimestampSec() - tsLogObj.timestampToday;
3✔
873
  if (delta >= 86400 || delta < 0) {
3!
874
    taosOpenNewSlowLogFile();
3✔
875
  }
876

877
  char   *buffer = taosMemoryMalloc(LOG_MAX_LINE_DUMP_BUFFER_SIZE);
3!
878
  int32_t len = taosBuildLogHead(buffer, "");
3✔
879

880
  va_list argpointer;
881
  va_start(argpointer, format);
3✔
882
  len += vsnprintf(buffer + len, LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 - len, format, argpointer);
3✔
883
  va_end(argpointer);
3✔
884

885
  if (len < 0 || len > LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2) {
3!
886
    len = LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2;
×
887
  }
888
  buffer[len++] = '\n';
3✔
889
  buffer[len] = 0;
3✔
890

891
  TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfSlowLogs, 1));
3✔
892

893
  if (tsAsyncLog) {
3!
894
    TAOS_UNUSED(taosPushLogBuffer(tsLogObj.slowHandle, buffer, len));
×
895
  } else {
896
    TAOS_UNUSED(taosWriteFile(tsLogObj.slowHandle->pFile, buffer, len));
3✔
897
  }
898

899
  taosMemoryFree(buffer);
3!
900
}
901

902
static void taosCloseLogByFd(TdFilePtr pFile) {
1✔
903
  if (pFile != NULL) {
1!
904
    taosUnLockLogFile(pFile);
1✔
905
    (void)taosCloseFile(&pFile);
1✔
906
  }
907
}
1✔
908

909
static SLogBuff *taosLogBuffNew(int32_t bufSize) {
13,699✔
910
  SLogBuff *pLogBuf = NULL;
13,699✔
911

912
  pLogBuf = taosMemoryCalloc(1, sizeof(SLogBuff));
13,699!
913
  if (pLogBuf == NULL) return NULL;
13,699!
914

915
  LOG_BUF_BUFFER(pLogBuf) = taosMemoryMalloc(bufSize);
13,699!
916
  if (LOG_BUF_BUFFER(pLogBuf) == NULL) goto _err;
13,699!
917

918
  LOG_BUF_START(pLogBuf) = LOG_BUF_END(pLogBuf) = 0;
13,699✔
919
  LOG_BUF_SIZE(pLogBuf) = bufSize;
13,699✔
920
  pLogBuf->minBuffSize = bufSize / 10;
13,699✔
921
  pLogBuf->stop = 0;
13,699✔
922
  pLogBuf->writeInterval = LOG_DEFAULT_INTERVAL;
13,699✔
923
  pLogBuf->lock = 0;
13,699✔
924
  if (taosThreadMutexInit(&LOG_BUF_MUTEX(pLogBuf), NULL) < 0) goto _err;
13,699!
925
  // tsem_init(&(pLogBuf->buffNotEmpty), 0, 0);
926

927
  return pLogBuf;
13,699✔
928

929
_err:
×
930
  taosMemoryFreeClear(LOG_BUF_BUFFER(pLogBuf));
×
931
  taosMemoryFreeClear(pLogBuf);
×
932
  return NULL;
×
933
}
934

935
static void taosCopyLogBuffer(SLogBuff *pLogBuf, int32_t start, int32_t end, const char *msg, int32_t msgLen) {
952,104✔
936
  if (start > end) {
952,104!
937
    memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, msgLen);
×
938
  } else {
939
    if (LOG_BUF_SIZE(pLogBuf) - end < msgLen) {
952,104!
940
      memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, LOG_BUF_SIZE(pLogBuf) - end);
×
941
      memcpy(LOG_BUF_BUFFER(pLogBuf), msg + LOG_BUF_SIZE(pLogBuf) - end, msgLen - LOG_BUF_SIZE(pLogBuf) + end);
×
942
    } else {
943
      memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, msgLen);
952,104✔
944
    }
945
  }
946
  LOG_BUF_END(pLogBuf) = (LOG_BUF_END(pLogBuf) + msgLen) % LOG_BUF_SIZE(pLogBuf);
952,104✔
947
}
952,104✔
948

949
static int32_t taosPushLogBuffer(SLogBuff *pLogBuf, const char *msg, int32_t msgLen) {
950,388✔
950
  int32_t        start = 0;
950,388✔
951
  int32_t        end = 0;
950,388✔
952
  int32_t        remainSize = 0;
950,388✔
953
  static int64_t lostLine = 0;
954
  char           tmpBuf[128];
955
  int32_t        tmpBufLen = 0;
950,388✔
956

957
  if (pLogBuf == NULL || pLogBuf->stop) return -1;
950,388!
958

959
  (void)taosThreadMutexLock(&LOG_BUF_MUTEX(pLogBuf));
950,427✔
960
  start = LOG_BUF_START(pLogBuf);
952,104✔
961
  end = LOG_BUF_END(pLogBuf);
952,104✔
962

963
  remainSize = (start > end) ? (start - end - 1) : (start + LOG_BUF_SIZE(pLogBuf) - end - 1);
952,104!
964

965
  if (lostLine > 0) {
952,104!
966
    tmpBufLen = snprintf(tmpBuf, tListLen(tmpBuf), "...Lost %" PRId64 " lines here...\n", lostLine);
×
967
  }
968

969
  if (remainSize <= msgLen || ((lostLine > 0) && (remainSize <= (msgLen + tmpBufLen)))) {
952,104!
970
    lostLine++;
×
971
    tsAsyncLogLostLines++;
×
972
    (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
×
973
    return -1;
×
974
  }
975

976
  if (lostLine > 0) {
952,104!
977
    taosCopyLogBuffer(pLogBuf, start, end, tmpBuf, tmpBufLen);
×
978
    lostLine = 0;
×
979
  }
980

981
  taosCopyLogBuffer(pLogBuf, LOG_BUF_START(pLogBuf), LOG_BUF_END(pLogBuf), msg, msgLen);
952,104✔
982

983
  // int32_t w = atomic_sub_fetch_32(&waitLock, 1);
984
  /*
985
  if (w <= 0 || ((remainSize - msgLen - tmpBufLen) < (LOG_BUF_SIZE(pLogBuf) * 4 /5))) {
986
    tsem_post(&(pLogBuf->buffNotEmpty));
987
    dbgPostN++;
988
  } else {
989
    dbgNoPostN++;
990
  }
991
  */
992

993
  (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
952,104✔
994

995
  return 0;
951,748✔
996
}
997

998
static int32_t taosGetLogRemainSize(SLogBuff *pLogBuf, int32_t start, int32_t end) {
91,822✔
999
  int32_t rSize = end - start;
91,822✔
1000

1001
  return rSize >= 0 ? rSize : LOG_BUF_SIZE(pLogBuf) + rSize;
91,822!
1002
}
1003

1004
static void taosWriteSlowLog(SLogBuff *pLogBuf) {
8,638,004✔
1005
  int32_t lock = atomic_val_compare_exchange_32(&pLogBuf->lock, 0, 1);
8,638,004✔
1006
  if (lock == 1) return;
8,638,004!
1007
  taosWriteLog(pLogBuf);
8,638,004✔
1008
  atomic_store_32(&pLogBuf->lock, 0);
8,638,004✔
1009
}
1010
static void taosWriteLog(SLogBuff *pLogBuf) {
17,299,667✔
1011
  (void)taosThreadMutexLock(&LOG_BUF_MUTEX(pLogBuf));
17,299,667✔
1012
  int32_t start = LOG_BUF_START(pLogBuf);
17,299,667✔
1013
  int32_t end = LOG_BUF_END(pLogBuf);
17,299,667✔
1014
  (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
17,299,667✔
1015

1016
  if (start == end) {
17,299,667✔
1017
    dbgEmptyW++;
17,211,453✔
1018
    pLogBuf->writeInterval = LOG_MAX_INTERVAL;
17,211,453✔
1019
    return;
17,211,453✔
1020
  }
1021

1022
  int32_t pollSize = taosGetLogRemainSize(pLogBuf, start, end);
88,214✔
1023
  if (pollSize < pLogBuf->minBuffSize) {
88,214!
1024
    pLogBuf->lastDuration += pLogBuf->writeInterval;
88,214✔
1025
    if (pLogBuf->lastDuration < LOG_MAX_WAIT_MSEC) {
88,214✔
1026
      return;
84,606✔
1027
    }
1028
  }
1029

1030
  pLogBuf->lastDuration = 0;
3,608✔
1031

1032
  if (start < end) {
3,608!
1033
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf) + start, pollSize));
3,608✔
1034
  } else {
1035
    int32_t tsize = LOG_BUF_SIZE(pLogBuf) - start;
×
1036
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf) + start, tsize));
×
1037

1038
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf), end));
×
1039
  }
1040

1041
  dbgWN++;
3,608✔
1042
  dbgWSize += pollSize;
3,608✔
1043

1044
  if (pollSize < pLogBuf->minBuffSize) {
3,608!
1045
    dbgSmallWN++;
3,608✔
1046
    if (pLogBuf->writeInterval < LOG_MAX_INTERVAL) {
3,608!
1047
      pLogBuf->writeInterval += LOG_INTERVAL_STEP;
×
1048
    }
1049
  } else if (pollSize > LOG_BUF_SIZE(pLogBuf) / 3) {
×
1050
    dbgBigWN++;
×
1051
    pLogBuf->writeInterval = LOG_MIN_INTERVAL;
×
1052
  } else if (pollSize > LOG_BUF_SIZE(pLogBuf) / 4) {
×
1053
    if (pLogBuf->writeInterval > LOG_MIN_INTERVAL) {
×
1054
      pLogBuf->writeInterval -= LOG_INTERVAL_STEP;
×
1055
    }
1056
  }
1057

1058
  (void)taosThreadMutexLock(&LOG_BUF_MUTEX(pLogBuf));
3,608✔
1059
  LOG_BUF_START(pLogBuf) = (LOG_BUF_START(pLogBuf) + pollSize) % LOG_BUF_SIZE(pLogBuf);
3,608✔
1060

1061
  start = LOG_BUF_START(pLogBuf);
3,608✔
1062
  end = LOG_BUF_END(pLogBuf);
3,608✔
1063
  (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
3,608✔
1064

1065
  pollSize = taosGetLogRemainSize(pLogBuf, start, end);
3,608✔
1066
  if (pollSize < pLogBuf->minBuffSize) {
3,608!
1067
    return;
3,608✔
1068
  }
1069

1070
  pLogBuf->writeInterval = 0;
×
1071
}
1072

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

1105
  taosWLockLatch(&tsLogRotateLatch);
4,417✔
1106
  // compress or remove the old log files
1107
  TdDirPtr pDir = taosOpenDir(tsLogDir);
4,417✔
1108
  if (!pDir) goto _exit;
4,417!
1109
  TdDirEntryPtr de = NULL;
4,417✔
1110
  while ((de = taosReadDir(pDir))) {
27,961✔
1111
    if (taosDirEntryIsDir(de)) {
23,544✔
1112
      continue;
23,544✔
1113
    }
1114
    char *fname = taosGetDirEntryName(de);
14,665✔
1115
    if (!fname) {
14,665!
1116
      continue;
×
1117
    }
1118

1119
    if (!strstr(fname, filePrefix)) continue;
14,665✔
1120

1121
    char *pSec = strrchr(fname, '.');
4,820✔
1122
    if (!pSec) {
4,820!
1123
      continue;
×
1124
    }
1125
    char *pIter = pSec;
4,820✔
1126
    bool  isSec = true;
4,820✔
1127
    while (*(++pIter)) {
9,640✔
1128
      if (!isdigit(*pIter)) {
4,820!
1129
        isSec = false;
×
1130
        break;
×
1131
      }
1132
    }
1133
    if (!isSec) {
4,820!
1134
      continue;
×
1135
    }
1136

1137
    int64_t fileSec = 0;
4,820✔
1138
    if ((code = taosStr2int64(pSec + 1, &fileSec)) != 0) {
4,820!
1139
      uWarn("%s:%d failed to convert %s to int64 since %s", __func__, __LINE__, pSec + 1, tstrerror(code));
×
1140
      continue;
×
1141
    }
1142
    if (fileSec <= 100) {
4,820!
1143
      continue;
4,820✔
1144
    }
1145

1146
    char fullName[PATH_MAX] = {0};
×
1147
    snprintf(fullName, sizeof(fullName), "%s%s%s", tsLogDir, TD_DIRSEP, fname);
×
1148

1149
    int64_t mtime = 0;
×
1150
    if ((code = taosStatFile(fullName, NULL, &mtime, NULL)) != 0) {
×
1151
      uWarn("%s:%d failed to stat file %s since %s", __func__, __LINE__, fullName, tstrerror(code));
×
1152
      continue;
×
1153
    }
1154

1155
    int64_t inactiveSec = taosGetTimestampMs() / 1000 - mtime;
×
1156

1157
    if (inactiveSec < LOG_INACTIVE_TIME) {
×
1158
      continue;
×
1159
    }
1160

1161
    int32_t days = inactiveSec / 86400 + 1;
×
1162
    if (tsLogKeepDays != 0 && days > abs(tsLogKeepDays)) {
×
1163
      TAOS_UNUSED(taosRemoveFile(fullName));
×
1164
      uInfo("file:%s is removed, days:%d, keepDays:%d, sed:%" PRId64, fullName, days, tsLogKeepDays, fileSec);
×
1165
    } else {
1166
      taosKeepOldLog(fullName);  // compress
×
1167
    }
1168
  }
1169
  if ((code = taosCloseDir(&pDir)) != 0) {
4,417!
1170
    uWarn("%s:%d failed to close dir %s since %s\n", __func__, __LINE__, tsLogDir, tstrerror(code));
×
1171
  }
1172

1173
  if (tsLogKeepDays != 0) {
4,417✔
1174
    taosRemoveOldFiles(tsLogDir, abs(tsLogKeepDays));
2✔
1175
  }
1176
_exit:
4,415✔
1177
  taosWUnLockLatch(&tsLogRotateLatch);
4,417✔
1178
  atomic_store_8(&tsLogRotateRunning, 0);
4,417✔
1179
  taosMemFreeClear(filePrefix);
4,417!
1180
  return NULL;
4,417✔
1181
}
1182

1183
static void *taosAsyncOutputLog(void *param) {
6,878✔
1184
  SLogBuff *pLogBuf = (SLogBuff *)tsLogObj.logHandle;
6,878✔
1185
  SLogBuff *pSlowBuf = (SLogBuff *)tsLogObj.slowHandle;
6,878✔
1186

1187
  setThreadName("log");
6,878✔
1188
  int32_t count = 0;
6,878✔
1189
  int32_t updateCron = 0;
6,878✔
1190
  int32_t writeInterval = 0;
6,878✔
1191
  int64_t lastCheckSec = taosGetTimestampMs() / 1000 - (LOG_ROTATE_INTERVAL - LOG_ROTATE_BOOT);
6,878✔
1192

1193
  while (1) {
8,647,946✔
1194
    if (pSlowBuf) {
8,654,824✔
1195
      writeInterval = TMIN(pLogBuf->writeInterval, pSlowBuf->writeInterval);
8,631,183✔
1196
    } else {
1197
      writeInterval = pLogBuf->writeInterval;
23,641✔
1198
    }
1199
    count += writeInterval;
8,654,824✔
1200
    updateCron++;
8,654,824✔
1201
    taosMsleep(writeInterval);
8,654,824✔
1202
    if (count > 1000) {
8,654,803✔
1203
      TAOS_UNUSED(osUpdate());
207,941✔
1204
      count = 0;
207,941✔
1205
    }
1206

1207
    // Polling the buffer
1208
    taosWriteLog(pLogBuf);
8,654,803✔
1209
    if (pSlowBuf) taosWriteSlowLog(pSlowBuf);
8,654,803✔
1210

1211
    if (pLogBuf->stop || (pSlowBuf && pSlowBuf->stop)) {
8,654,803!
1212
      pLogBuf->lastDuration = LOG_MAX_WAIT_MSEC;
6,857✔
1213
      taosWriteLog(pLogBuf);
6,857✔
1214
      if (pSlowBuf) taosWriteSlowLog(pSlowBuf);
6,857✔
1215
      break;
6,857✔
1216
    }
1217

1218
    // process the log rotation every LOG_ROTATE_INTERVAL
1219
    int64_t curSec = taosGetTimestampMs() / 1000;
8,647,946✔
1220
    if (curSec >= lastCheckSec) {
8,647,946!
1221
      if ((curSec - lastCheckSec) >= (LOG_ROTATE_INTERVAL + (taosRand() % LOG_ROTATE_BOOT))) {
8,647,946✔
1222
        TdThread     thread;
1223
        TdThreadAttr attr;
1224
        (void)taosThreadAttrInit(&attr);
4,417✔
1225
        (void)taosThreadAttrSetDetachState(&attr, PTHREAD_CREATE_DETACHED);
4,417✔
1226
#ifdef TD_COMPACT_OS
1227
        (void)taosThreadAttrSetStackSize(&attr, STACK_SIZE_SMALL);
1228
#endif
1229
        if (taosThreadCreate(&thread, &attr, taosLogRotateFunc, tsLogObj.logHandle) == 0) {
4,417!
1230
          uInfo("process log rotation");
4,417!
1231
          lastCheckSec = curSec;
4,417✔
1232
        } else {
1233
          uWarn("failed to create thread to process log rotation");
×
1234
        }
1235
        (void)taosThreadAttrDestroy(&attr);
4,417✔
1236
      }
1237
    } else if (curSec < lastCheckSec) {
×
1238
      lastCheckSec = curSec;
×
1239
    }
1240
  }
1241

1242
  return NULL;
6,857✔
1243
}
1244

1245
bool taosAssertDebug(bool condition, const char *file, int32_t line, bool core, const char *format, ...) {
6✔
1246
  if (condition) return false;
6✔
1247

1248
  const char *flags = "UTL FATAL ";
3✔
1249
  ELogLevel   level = DEBUG_FATAL;
3✔
1250
  int32_t     dflag = 255;  // tsLogEmbedded ? 255 : uDebugFlag
3✔
1251
  char        buffer[LOG_MAX_LINE_BUFFER_SIZE];
1252
  int32_t     len = taosBuildLogHead(buffer, flags);
3✔
1253

1254
  va_list argpointer;
1255
  va_start(argpointer, format);
3✔
1256
  len = len + vsnprintf(buffer + len, LOG_MAX_LINE_BUFFER_SIZE - len, format, argpointer);
3✔
1257
  va_end(argpointer);
3✔
1258
  buffer[len++] = '\n';
3✔
1259
  buffer[len] = 0;
3✔
1260
  taosPrintLogImp(1, 255, buffer, len);
3✔
1261

1262
  taosPrintLog(flags, level, dflag, "tAssert at file %s:%d exit:%d", file, line, tsAssert);
3✔
1263
#ifndef TD_ASTRA
1264
  taosPrintTrace(flags, level, dflag, -1);
51!
1265
#endif
1266
  if (tsAssert || core) {
3!
1267
    taosCloseLog();
×
1268
    taosMsleep(300);
×
1269

1270
#ifdef NDEBUG
1271
    abort();
1272
#else
1273
    assert(0);
×
1274
#endif
1275
  }
1276

1277
  return true;
3✔
1278
}
1279
#ifdef USE_REPORT
1280
void taosLogCrashInfo(char *nodeType, char *pMsg, int64_t msgLen, int signum, void *sigInfo) {
6✔
1281
  const char *flags = "UTL FATAL ";
6✔
1282
  ELogLevel   level = DEBUG_FATAL;
6✔
1283
  int32_t     dflag = 255;
6✔
1284
  char        filepath[PATH_MAX] = {0};
6✔
1285
  TdFilePtr   pFile = NULL;
6✔
1286

1287
  if (pMsg && msgLen > 0) {
6!
1288
    snprintf(filepath, sizeof(filepath), "%s%s.%sCrashLog", tsLogDir, TD_DIRSEP, nodeType);
3✔
1289

1290
    pFile = taosOpenFile(filepath, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_APPEND);
3✔
1291
    if (pFile == NULL) {
3!
1292
      taosPrintLog(flags, level, dflag, "failed to open file:%s since %s", filepath, terrstr());
×
1293
      goto _return;
×
1294
    }
1295

1296
    if (taosLockFile(pFile) < 0) {
3!
1297
      taosPrintLog(flags, level, dflag, "failed to lock file:%s since %s", filepath, terrstr());
×
1298
      goto _return;
×
1299
    }
1300

1301
    int64_t writeSize = taosWriteFile(pFile, &msgLen, sizeof(msgLen));
3✔
1302
    if (sizeof(msgLen) != writeSize) {
3!
1303
      TAOS_UNUSED(taosUnLockFile(pFile));
×
1304
      taosPrintLog(flags, level, dflag, "failed to write len to file:%s,%p wlen:%" PRId64 " tlen:%lu since %s",
×
1305
                   filepath, pFile, writeSize, sizeof(msgLen), terrstr());
1306
      goto _return;
×
1307
    }
1308

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

1317
    TAOS_UNUSED(taosUnLockFile(pFile));
3✔
1318
  }
1319

1320
_return:
3✔
1321

1322
  if (pFile) (void)taosCloseFile(&pFile);
6✔
1323

1324
  taosPrintLog(flags, level, dflag, "crash signal is %d", signum);
6✔
1325

1326
// print the stack trace
1327
#if 0
1328
#ifdef _TD_DARWIN_64
1329
  taosPrintTrace(flags, level, dflag, 4);
1330
#elif !defined(WINDOWS)
1331
  taosPrintLog(flags, level, dflag, "sender PID:%d cmdline:%s", ((siginfo_t *)sigInfo)->si_pid,
1332
               taosGetCmdlineByPID(((siginfo_t *)sigInfo)->si_pid));
1333
  taosPrintTrace(flags, level, dflag, 3);
1334
#else
1335
  taosPrintTrace(flags, level, dflag, 8);
1336
#endif
1337
#endif
1338
  taosMemoryFree(pMsg);
6!
1339
}
6✔
1340

1341
typedef enum {
1342
  CRASH_LOG_WRITER_UNKNOWN = 0,
1343
  CRASH_LOG_WRITER_INIT = 1,
1344
  CRASH_LOG_WRITER_WAIT,
1345
  CRASH_LOG_WRITER_RUNNING,
1346
  CRASH_LOG_WRITER_QUIT
1347
} CrashStatus;
1348
typedef struct crashBasicInfo {
1349
  int8_t  status;
1350
  int64_t clusterId;
1351
  int64_t startTime;
1352
  char   *nodeType;
1353
  int     signum;
1354
  void   *sigInfo;
1355
  tsem_t  sem;
1356
  int64_t reportThread;
1357
} crashBasicInfo;
1358

1359
crashBasicInfo gCrashBasicInfo = {0};
1360

1361
void setCrashWriterStatus(int8_t status) { atomic_store_8(&gCrashBasicInfo.status, status); }
6✔
1362
bool reportThreadSetQuit() {
×
1363
  CrashStatus status =
×
1364
      atomic_val_compare_exchange_8(&gCrashBasicInfo.status, CRASH_LOG_WRITER_INIT, CRASH_LOG_WRITER_QUIT);
×
1365
  if (status == CRASH_LOG_WRITER_INIT) {
×
1366
    return true;
×
1367
  } else {
1368
    return false;
×
1369
  }
1370
}
1371

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

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

1415
void checkAndPrepareCrashInfo() {
3✔
1416
  return checkWriteCrashLogToFileInNewThead();
3✔
1417
}
1418

1419
int32_t initCrashLogWriter() {
3✔
1420
  int32_t code = tsem_init(&gCrashBasicInfo.sem, 0, 0);
3✔
1421
  if (code != 0) {
3!
1422
    uError("failed to init sem for crashLogWriter, code:%d", code);
×
1423
    return code;
×
1424
  }
1425
  gCrashBasicInfo.reportThread = taosGetSelfPthreadId();
3✔
1426
  setCrashWriterStatus(CRASH_LOG_WRITER_INIT);
3✔
1427
  return code;
3✔
1428
}
1429

1430
void writeCrashLogToFile(int signum, void *sigInfo, char *nodeType, int64_t clusterId, int64_t startTime) {
6✔
1431
  if (gCrashBasicInfo.reportThread == taosGetSelfPthreadId()) {
6✔
1432
    return;
3✔
1433
  }
1434
  if (setReportThreadWait()) {
3!
1435
    gCrashBasicInfo.clusterId = clusterId;
3✔
1436
    gCrashBasicInfo.startTime = startTime;
3✔
1437
    gCrashBasicInfo.nodeType = nodeType;
3✔
1438
    gCrashBasicInfo.signum = signum;
3✔
1439
    gCrashBasicInfo.sigInfo = sigInfo;
3✔
1440
    TAOS_UNUSED(tsem_wait(&gCrashBasicInfo.sem));
3✔
1441
  }
1442
}
1443

1444
void taosReadCrashInfo(char *filepath, char **pMsg, int64_t *pMsgLen, TdFilePtr *pFd) {
6✔
1445
  const char *flags = "UTL FATAL ";
6✔
1446
  ELogLevel   level = DEBUG_FATAL;
6✔
1447
  int32_t     dflag = 255;
6✔
1448
  TdFilePtr   pFile = NULL;
6✔
1449
  bool        truncateFile = false;
6✔
1450
  char       *buf = NULL;
6✔
1451

1452
  if (NULL == *pFd) {
6!
1453
    int64_t filesize = 0;
6✔
1454
    if (taosStatFile(filepath, &filesize, NULL, NULL) < 0) {
6!
1455
      if (TAOS_SYSTEM_ERROR(ENOENT) == terrno) {
×
1456
        return;
×
1457
      }
1458

1459
      taosPrintLog(flags, level, dflag, "failed to stat file:%s since %s", filepath, terrstr());
×
1460
      return;
×
1461
    }
1462

1463
    if (filesize <= 0) {
6!
1464
      return;
×
1465
    }
1466

1467
    pFile = taosOpenFile(filepath, TD_FILE_READ | TD_FILE_WRITE);
6✔
1468
    if (pFile == NULL) {
6!
1469
      if (ENOENT == ERRNO) {
×
1470
        return;
×
1471
      }
1472

1473
      taosPrintLog(flags, level, dflag, "failed to open file:%s since %s", filepath, terrstr());
×
1474
      return;
×
1475
    }
1476

1477
    TAOS_UNUSED(taosLockFile(pFile));
6✔
1478
  } else {
1479
    pFile = *pFd;
×
1480
  }
1481

1482
  int64_t msgLen = 0;
6✔
1483
  int64_t readSize = taosReadFile(pFile, &msgLen, sizeof(msgLen));
6✔
1484
  if (sizeof(msgLen) != readSize) {
6!
1485
    truncateFile = true;
×
1486
    if (readSize < 0) {
×
1487
      taosPrintLog(flags, level, dflag, "failed to read len from file:%s,%p wlen:%" PRId64 " tlen:%lu since %s",
×
1488
                   filepath, pFile, readSize, sizeof(msgLen), terrstr());
1489
    }
1490
    goto _return;
×
1491
  }
1492

1493
  buf = taosMemoryMalloc(msgLen);
6!
1494
  if (NULL == buf) {
6!
1495
    taosPrintLog(flags, level, dflag, "failed to malloc buf, size:%" PRId64, msgLen);
×
1496
    goto _return;
×
1497
  }
1498

1499
  readSize = taosReadFile(pFile, buf, msgLen);
6✔
1500
  if (msgLen != readSize) {
6✔
1501
    truncateFile = true;
3✔
1502
    taosPrintLog(flags, level, dflag, "failed to read file:%s,%p wlen:%" PRId64 " tlen:%" PRId64 " since %s", filepath,
3✔
1503
                 pFile, readSize, msgLen, terrstr());
1504
    goto _return;
3✔
1505
  }
1506

1507
  *pMsg = buf;
3✔
1508
  *pMsgLen = msgLen;
3✔
1509
  *pFd = pFile;
3✔
1510

1511
  return;
3✔
1512

1513
_return:
3✔
1514

1515
  if (truncateFile) {
3!
1516
    TAOS_UNUSED(taosFtruncateFile(pFile, 0));
3✔
1517
  }
1518
  TAOS_UNUSED(taosUnLockFile(pFile));
3✔
1519
  TAOS_UNUSED(taosCloseFile(&pFile));
3✔
1520
  taosMemoryFree(buf);
3!
1521

1522
  *pMsg = NULL;
3✔
1523
  *pMsgLen = 0;
3✔
1524
  *pFd = NULL;
3✔
1525
}
1526

1527
void taosReleaseCrashLogFile(TdFilePtr pFile, bool truncateFile) {
3✔
1528
  if (truncateFile) {
3!
1529
    TAOS_UNUSED(taosFtruncateFile(pFile, 0));
3✔
1530
  }
1531

1532
  TAOS_UNUSED(taosUnLockFile(pFile));
3✔
1533
  TAOS_UNUSED(taosCloseFile(&pFile));
3✔
1534
}
3✔
1535
#endif // USE_REPORT
1536

1537
#ifdef NDEBUG
1538
bool taosAssertRelease(bool condition) {
1539
  if (condition) return false;
1540

1541
  const char *flags = "UTL FATAL ";
1542
  ELogLevel   level = DEBUG_FATAL;
1543
  int32_t     dflag = 255;  // tsLogEmbedded ? 255 : uDebugFlag
1544

1545
  taosPrintLog(flags, level, dflag, "tAssert called in release mode, exit:%d", tsAssert);
1546
  taosPrintTrace(flags, level, dflag, 0);
1547

1548
  if (tsAssert) {
1549
    taosMsleep(300);
1550
    abort();
1551
  }
1552

1553
  return true;
1554
}
1555
#endif
1556

1557
#define NUM_BASE 100
1558
#define DIGIT_LENGTH 2
1559
#define MAX_DIGITS 24
1560

1561
char* u64toaFastLut(uint64_t val, char* buf) {
5,498✔
1562
  // Look-up table for 2-digit numbers
1563
  static const char* lut =
1564
      "0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455"
1565
      "5657585960616263646566676869707172737475767778798081828384858687888990919293949596979899";
1566

1567
  char  temp[MAX_DIGITS];
1568
  char* p = temp + tListLen(temp);
5,498✔
1569

1570
  // Process the digits greater than or equal to 100
1571
  while (val >= NUM_BASE) {
54,480✔
1572
    // Get the last 2 digits from the look-up table and add to the buffer
1573
    p -= DIGIT_LENGTH;
48,982✔
1574
    strncpy(p, lut + (val % NUM_BASE) * DIGIT_LENGTH, DIGIT_LENGTH);
48,982✔
1575
    val /= NUM_BASE;
48,982✔
1576
  }
1577

1578
  // Process the remaining 1 or 2 digits
1579
  if (val >= 10) {
5,498✔
1580
    // If the number is 10 or more, get the 2 digits from the look-up table
1581
    p -= DIGIT_LENGTH;
2,822✔
1582
    strncpy(p, lut + val * DIGIT_LENGTH, DIGIT_LENGTH);
2,822✔
1583
  } else if (val > 0 || p == temp) {
2,676!
1584
    // If the number is less than 10, add the single digit to the buffer
1585
    p -= 1;
2,681✔
1586
    *p = val + '0';
2,681✔
1587
  }
1588

1589
  int64_t len = temp + tListLen(temp) - p;
5,498✔
1590
  if (len > 0) {
5,498!
1591
    memcpy(buf, p, len);
5,499✔
1592
  } else {
1593
    buf[0] = '0';
×
1594
    len = 1;
×
1595
  }
1596
  buf[len] = '\0';
5,498✔
1597

1598
  return buf + len;
5,498✔
1599
}
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

© 2025 Coveralls, Inc