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

taosdata / TDengine / #4506

15 Jul 2025 12:33AM UTC coverage: 62.026% (-0.7%) from 62.706%
#4506

push

travis-ci

web-flow
docs: update stream docs (#31874)

155391 of 320094 branches covered (48.55%)

Branch coverage included in aggregate %.

240721 of 318525 relevant lines covered (75.57%)

6529048.03 hits per line

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

65.65
/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

145
int32_t tqClientDebugFlag = 131;
146

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

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

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

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

187
static void getFullPathName(char *fullName, const char *logName) {
46,703✔
188
  if (strlen(tsLogDir) != 0) {
46,703!
189
    char lastC = tsLogDir[strlen(tsLogDir) - 1];
46,703✔
190
    if (lastC == '\\' || lastC == '/') {
46,703!
191
      snprintf(fullName, PATH_MAX,
29,738✔
192
               "%s"
193
               "%s",
194
               tsLogDir, logName);
195
    } else {
196
      snprintf(fullName, PATH_MAX, "%s" TD_DIRSEP "%s", tsLogDir, logName);
16,965✔
197
    }
198
  } else {
199
    snprintf(fullName, PATH_MAX, "%s", logName);
×
200
  }
201
}
46,703✔
202

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

211
  getFullPathName(tsLogObj.slowLogName, logFileName);
23,342✔
212

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

222
  tsLogObj.timestampToday = taosGetTimestampToday(TSDB_TIME_PRECISION_SECONDS, NULL);
23,342✔
223
  tsLogObj.slowHandle = taosLogBuffNew(LOG_SLOW_BUF_SIZE);
23,342✔
224
  if (tsLogObj.slowHandle == NULL) return terrno;
23,342!
225

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

233
  return 0;
23,342✔
234
}
235

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

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

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

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

295
  if (tsLogObj.outputType == LOG_OUTPUT_STDOUT || tsLogObj.outputType == LOG_OUTPUT_STDERR ||
23,364✔
296
      tsLogObj.outputType == LOG_OUTPUT_NULL) {
23,361!
297
    return 0;
3✔
298
  }
299

300
  TAOS_CHECK_RETURN(taosInitNormalLog(logName, maxFiles));
23,361!
301
  if (tsc) {
23,361✔
302
    TAOS_CHECK_RETURN(taosInitSlowLog());
23,342!
303
  }
304
  TAOS_CHECK_RETURN(taosStartLog());
23,361!
305
  return 0;
23,361✔
306
}
307

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

310
static void taosStopLog() {
23,357✔
311
  if (tsLogObj.logHandle) {
23,357✔
312
    tsLogObj.logHandle->stop = 1;
23,352✔
313
  }
314
  if (tsLogObj.slowHandle) {
23,357✔
315
    tsLogObj.slowHandle->stop = 1;
23,340✔
316
  }
317
}
23,357✔
318

319
void taosCloseLog() {
23,357✔
320
  taosStopLog();
23,357✔
321

322
  if (tsLogObj.logHandle != NULL && taosCheckPthreadValid(tsLogObj.logHandle->asyncThread)) {
23,357!
323
    (void)taosThreadJoin(tsLogObj.logHandle->asyncThread, NULL);
23,352✔
324
    taosThreadClear(&tsLogObj.logHandle->asyncThread);
23,352✔
325
  }
326

327
  if (tsLogObj.slowHandle != NULL) {
23,357✔
328
    (void)taosThreadMutexDestroy(&tsLogObj.slowHandle->buffMutex);
23,340✔
329
    (void)taosCloseFile(&tsLogObj.slowHandle->pFile);
23,340✔
330
    taosMemoryFreeClear(tsLogObj.slowHandle->buffer);
23,340!
331
    taosMemoryFreeClear(tsLogObj.slowHandle);
23,340!
332
  }
333

334
  if (tsLogObj.logHandle != NULL) {
23,357✔
335
    tsLogInited = 0;
23,352✔
336

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

347
static bool taosLockLogFile(TdFilePtr pFile) {
49,920✔
348
  if (pFile == NULL) return false;
49,920!
349

350
  if (tsLogObj.fileNum > 1) {
49,920✔
351
    int32_t ret = taosLockFile(pFile);
43,604✔
352
    if (ret == 0) {
43,604✔
353
      return true;
32,144✔
354
    }
355
  }
356

357
  return false;
17,776✔
358
}
359

360
static void taosUnLockLogFile(TdFilePtr pFile) {
15,263✔
361
  if (pFile == NULL) return;
15,263!
362

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

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

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

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

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

427
  TAOS_UNUSED(taosUmaskFile(0));
3✔
428

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

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

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

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

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

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

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

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

502
  (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
3✔
503

504
  return 0;
3✔
505
}
506

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

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

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

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

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

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

563
void taosLogObjSetToday(int64_t ts) { tsLogObj.timestampToday = ts; }
1✔
564

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

576
  if (taosLockLogFile(pFile)) {
26,556✔
577
    taosUnLockLogFile(pFile);
15,263✔
578
    (void)taosCloseFile(&pFile);
15,263✔
579
    return false;
15,263✔
580
  } else {
581
    (void)taosCloseFile(&pFile);
11,293✔
582
    return true;
11,293✔
583
  }
584
}
585

586
static void decideLogFileName(const char *fn, int32_t maxFileNum) {
23,361✔
587
  tsLogObj.fileNum = maxFileNum;
23,361✔
588
  if (tsLogObj.fileNum > 1) {
23,361✔
589
    for (int32_t i = 0; i < tsLogObj.fileNum; i++) {
28,340✔
590
      char fileName[PATH_MAX + 10];
591

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

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

598
      if (!file1open && !file2open) {
28,211!
599
        (void)snprintf(tsLogObj.logName, PATH_MAX, "%s%d", fn, i);
16,918✔
600
        return;
16,918✔
601
      }
602
    }
603
  }
604

605
  if (strlen(fn) < PATH_MAX) {
6,443!
606
    tstrncpy(tsLogObj.logName, fn, PATH_MAX);
6,443✔
607
  }
608
}
609

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

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

625
  // if none of the log files exist, open 0, if both exists, open the old one
626
  if (!log0Exist && !log1Exist) {
23,361!
627
    tsLogObj.flag = 0;
6,846✔
628
  } else if (!log1Exist) {
16,515✔
629
    tsLogObj.flag = 0;
16,468✔
630
  } else if (!log0Exist) {
47!
631
    tsLogObj.flag = 1;
×
632
  } else {
633
    tsLogObj.flag = (logstat0_mtime > logstat1_mtime) ? 0 : 1;
47✔
634
  }
635
}
23,361✔
636

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

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

654
  processLogFileName(logName, maxFileNum);
23,361✔
655

656
  int32_t logNameLen = strlen(tsLogObj.logName) + 2;  // logName + ".0" or ".1"
23,361✔
657

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

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

667
  TAOS_UNUSED(taosUmaskFile(0));
23,361✔
668
  tsLogObj.logHandle = taosLogBuffNew(LOG_DEFAULT_BUF_SIZE);
23,361✔
669
  if (tsLogObj.logHandle == NULL) return terrno;
23,361!
670

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

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

682
  tsLogObj.lines = (int32_t)(filesize / 60);
23,361✔
683

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

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

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

704
static void taosUpdateLogNums(ELogLevel level) {
661,103,787✔
705
  switch (level) {
661,103,787!
706
    case DEBUG_ERROR:
780,380✔
707
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfErrorLogs, 1));
780,380✔
708
      break;
780,396✔
709
    case DEBUG_INFO:
26,529,339✔
710
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfInfoLogs, 1));
26,529,339✔
711
      break;
26,549,296✔
712
    case DEBUG_DEBUG:
353,834,533✔
713
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfDebugLogs, 1));
353,834,533✔
714
      break;
353,982,999✔
715
    case DEBUG_DUMP:
280,001,290✔
716
    case DEBUG_TRACE:
717
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfTraceLogs, 1));
280,001,290✔
718
      break;
280,049,868✔
719
    default:
×
720
      break;
×
721
  }
722
}
661,320,804✔
723

724
static inline int32_t taosBuildLogHead(char *buffer, const char *flags) {
662,553,938✔
725
  struct tm      Tm, *ptm;
726
  struct timeval timeSecs;
727

728
  TAOS_UNUSED(taosGetTimeOfDay(&timeSecs));
662,553,938✔
729
  time_t curTime = timeSecs.tv_sec;
662,489,859✔
730
  ptm = taosLocalTime(&curTime, &Tm, NULL, 0, NULL);
662,489,859✔
731
  if (ptm == NULL) {
662,755,787!
732
    uError("%s failed to get local time, code:%d", __FUNCTION__, ERRNO);
×
733
    return 0;
×
734
  }
735
  return snprintf(buffer, LOG_MAX_STACK_LINE_BUFFER_SIZE, "%02d/%02d %02d:%02d:%02d.%06d %08" PRId64 " %s %s",
662,755,787✔
736
                  ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int32_t)timeSecs.tv_usec,
662,746,469✔
737
                  taosGetSelfPthreadId(), LOG_EDITION_FLG, flags);
738
}
739

740
static inline void taosPrintLogImp(ELogLevel level, int32_t dflag, const char *buffer, int32_t len) {
661,614,967✔
741
  if ((dflag & DEBUG_FILE) && tsLogObj.logHandle && tsLogObj.logHandle->pFile != NULL && osLogSpaceSufficient()) {
661,614,967!
742
    taosUpdateLogNums(level);
661,119,289✔
743
    if (tsAsyncLog) {
661,328,474✔
744
      TAOS_UNUSED(taosPushLogBuffer(tsLogObj.logHandle, buffer, len));
5,226,100✔
745
    } else {
746
      TAOS_UNUSED(taosWriteFile(tsLogObj.logHandle->pFile, buffer, len));
656,102,374✔
747
    }
748

749
    if (tsNumOfLogLines > 0) {
661,360,634!
750
      TAOS_UNUSED(atomic_add_fetch_32(&tsLogObj.lines, 1));
661,367,379✔
751
      if ((tsLogObj.lines > tsNumOfLogLines) && (tsLogObj.openInProgress == 0)) {
661,383,856!
752
        TAOS_UNUSED(taosOpenNewLogFile());
×
753
      }
754
    }
755
  }
756

757
  int fd = 0;
661,873,599✔
758
  if (tsLogObj.outputType == LOG_OUTPUT_FILE) {
661,873,599✔
759
#ifndef TAOSD_INTEGRATED    
760
    if (dflag & DEBUG_SCREEN) fd = 1;
661,872,706✔
761
#else
762
    if ((dflag & DEBUG_SCREEN) && tsLogEmbedded) fd = 1;
763
#endif
764
  } else if (tsLogObj.outputType == LOG_OUTPUT_STDOUT) {
893✔
765
    fd = 1;
583✔
766
  } else if (tsLogObj.outputType == LOG_OUTPUT_STDERR) {
310✔
767
    fd = 2;
289✔
768
  }
769

770
  if (fd) {
661,873,599✔
771
#pragma GCC diagnostic push
772
#pragma GCC diagnostic ignored "-Wunused-result"
773
#ifndef TD_ASTRA
774
    if (write(fd, buffer, (uint32_t)len) < 0) {
14,065,040✔
775
      TAOS_UNUSED(printf("failed to write log to screen, reason:%s\n", strerror(ERRNO)));
176,731✔
776
    }
777
#else
778
    TAOS_UNUSED(fprintf(fd == 1 ? stdout : stderr, "%s", buffer));
779
#endif
780
#pragma GCC diagnostic pop
781
  }
782
}
661,873,538✔
783

784
/*
785
  use taosPrintLogImpl_useStackBuffer to avoid stack overflow
786

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

793
  int32_t writeLen = len + vsnprintf(buffer + len, LOG_MAX_STACK_LINE_BUFFER_SIZE - len - 1, format, args);
661,674,736✔
794
  if (writeLen > LOG_MAX_STACK_LINE_SIZE) {
661,674,736✔
795
    return 1;
886,596✔
796
  }
797

798
  buffer[writeLen++] = '\n';
660,788,140✔
799
  buffer[writeLen] = 0;
660,788,140✔
800

801
  taosPrintLogImp(level, dflag, buffer, writeLen);
660,788,140✔
802

803
  if (tsLogFp && level <= DEBUG_INFO) {
660,991,592✔
804
    buffer[writeLen - 1] = 0;
11,974,735✔
805
    (*tsLogFp)(taosGetTimestampMs(), level, buffer + len);
23,949,286✔
806
  }
807
  return 0;
660,995,803✔
808
}
809
static int8_t taosPrintLogImplUseHeapBuffer(const char *flags, int32_t level, int32_t dflag, const char *format,
886,556✔
810
                                            va_list args) {
811
  char *buffer = taosMemoryCalloc(1, LOG_MAX_LINE_BUFFER_SIZE + 1);
886,556!
812
  if (buffer == NULL) {
886,616!
813
    return 1;
×
814
  }
815
  int32_t len = taosBuildLogHead(buffer, flags);
886,616✔
816

817
  int32_t writeLen = len + vsnprintf(buffer + len, LOG_MAX_LINE_BUFFER_SIZE - len - 1, format, args);
886,639✔
818

819
  if (writeLen > LOG_MAX_LINE_SIZE) writeLen = LOG_MAX_LINE_SIZE;
886,639✔
820
  buffer[writeLen++] = '\n';
886,639✔
821
  buffer[writeLen] = 0;
886,639✔
822

823
  taosPrintLogImp(level, dflag, buffer, writeLen);
886,639✔
824

825
  if (tsLogFp && level <= DEBUG_INFO) {
886,641✔
826
    buffer[writeLen - 1] = 0;
92,168✔
827
    (*tsLogFp)(taosGetTimestampMs(), level, buffer + len);
184,336✔
828
  }
829
  taosMemoryFree(buffer);
886,641!
830
  return 0;
886,640✔
831
}
832
void taosPrintLog(const char *flags, int32_t level, int32_t dflag, const char *format, ...) {
661,411,811✔
833
  if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return;
661,411,811!
834

835
  va_list argpointer, argpointer_copy;
836
  va_start(argpointer, format);
661,411,811✔
837
  va_copy(argpointer_copy, argpointer);
661,411,811✔
838

839
  if (taosPrintLogImplUseStackBuffer(flags, level, dflag, format, argpointer) == 0) {
661,411,811✔
840
  } else {
841
    TAOS_UNUSED(taosPrintLogImplUseHeapBuffer(flags, level, dflag, format, argpointer_copy));
886,545✔
842
  }
843
  va_end(argpointer_copy);
661,883,294✔
844
  va_end(argpointer);
661,883,294✔
845
}
846

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

851
  char *buffer = taosMemoryMalloc(LOG_MAX_LINE_DUMP_BUFFER_SIZE);
2,799!
852
  if (!buffer) return;
2,799!
853
  int32_t len = taosBuildLogHead(buffer, flags);
2,799✔
854

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

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

864
  taosPrintLogImp(level, dflag, buffer, len);
2,799✔
865
  taosMemoryFree(buffer);
2,799!
866
}
867

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

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

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

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

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

890
  TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfSlowLogs, 1));
350✔
891

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

898
  taosMemoryFree(buffer);
350!
899
}
900

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

908
static SLogBuff *taosLogBuffNew(int32_t bufSize) {
46,703✔
909
  SLogBuff *pLogBuf = NULL;
46,703✔
910

911
  pLogBuf = taosMemoryCalloc(1, sizeof(SLogBuff));
46,703!
912
  if (pLogBuf == NULL) return NULL;
46,703!
913

914
  LOG_BUF_BUFFER(pLogBuf) = taosMemoryMalloc(bufSize);
46,703!
915
  if (LOG_BUF_BUFFER(pLogBuf) == NULL) goto _err;
46,703!
916

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

926
  return pLogBuf;
46,703✔
927

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

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

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

956
  if (pLogBuf == NULL || pLogBuf->stop) return -1;
5,222,075!
957

958
  (void)taosThreadMutexLock(&LOG_BUF_MUTEX(pLogBuf));
5,220,382✔
959
  start = LOG_BUF_START(pLogBuf);
5,232,407✔
960
  end = LOG_BUF_END(pLogBuf);
5,232,407✔
961

962
  remainSize = (start > end) ? (start - end - 1) : (start + LOG_BUF_SIZE(pLogBuf) - end - 1);
5,232,407!
963

964
  if (lostLine > 0) {
5,232,407!
965
    snprintf(tmpBuf, tListLen(tmpBuf), "...Lost %" PRId64 " lines here...\n", lostLine);
×
966
    tmpBufLen = (int32_t)strlen(tmpBuf);
×
967
  }
968

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

976
  if (lostLine > 0) {
5,232,407!
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);
5,232,407✔
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));
5,232,407✔
994

995
  return 0;
5,229,121✔
996
}
997

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

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

1004
static void taosWriteSlowLog(SLogBuff *pLogBuf) {
14,156,485✔
1005
  int32_t lock = atomic_val_compare_exchange_32(&pLogBuf->lock, 0, 1);
14,156,485✔
1006
  if (lock == 1) return;
14,156,485!
1007
  taosWriteLog(pLogBuf);
14,156,485✔
1008
  atomic_store_32(&pLogBuf->lock, 0);
14,156,485✔
1009
}
1010
static void taosWriteLog(SLogBuff *pLogBuf) {
28,321,329✔
1011
  int32_t start = LOG_BUF_START(pLogBuf);
28,321,329✔
1012
  int32_t end = LOG_BUF_END(pLogBuf);
28,321,329✔
1013

1014
  if (start == end) {
28,321,329✔
1015
    dbgEmptyW++;
28,115,281✔
1016
    pLogBuf->writeInterval = LOG_MAX_INTERVAL;
28,115,281✔
1017
    return;
28,115,281✔
1018
  }
1019

1020
  int32_t pollSize = taosGetLogRemainSize(pLogBuf, start, end);
206,048✔
1021
  if (pollSize < pLogBuf->minBuffSize) {
206,048!
1022
    pLogBuf->lastDuration += pLogBuf->writeInterval;
206,048✔
1023
    if (pLogBuf->lastDuration < LOG_MAX_WAIT_MSEC) {
206,048✔
1024
      return;
188,794✔
1025
    }
1026
  }
1027

1028
  pLogBuf->lastDuration = 0;
17,254✔
1029

1030
  if (start < end) {
17,254!
1031
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf) + start, pollSize));
17,254✔
1032
  } else {
1033
    int32_t tsize = LOG_BUF_SIZE(pLogBuf) - start;
×
1034
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf) + start, tsize));
×
1035

1036
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf), end));
×
1037
  }
1038

1039
  dbgWN++;
17,254✔
1040
  dbgWSize += pollSize;
17,254✔
1041

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

1056
  LOG_BUF_START(pLogBuf) = (LOG_BUF_START(pLogBuf) + pollSize) % LOG_BUF_SIZE(pLogBuf);
17,254✔
1057

1058
  start = LOG_BUF_START(pLogBuf);
17,254✔
1059
  end = LOG_BUF_END(pLogBuf);
17,254✔
1060

1061
  pollSize = taosGetLogRemainSize(pLogBuf, start, end);
17,254✔
1062
  if (pollSize < pLogBuf->minBuffSize) {
17,254!
1063
    return;
17,254✔
1064
  }
1065

1066
  pLogBuf->writeInterval = 0;
×
1067
}
1068

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

1101
  taosWLockLatch(&tsLogRotateLatch);
7,860✔
1102
  // compress or remove the old log files
1103
  TdDirPtr pDir = taosOpenDir(tsLogDir);
7,860✔
1104
  if (!pDir) goto _exit;
7,860!
1105
  TdDirEntryPtr de = NULL;
7,860✔
1106
  while ((de = taosReadDir(pDir))) {
49,163✔
1107
    if (taosDirEntryIsDir(de)) {
41,303✔
1108
      continue;
41,303✔
1109
    }
1110
    char *fname = taosGetDirEntryName(de);
25,579✔
1111
    if (!fname) {
25,579!
1112
      continue;
×
1113
    }
1114

1115
    if (!strstr(fname, filePrefix)) continue;
25,579✔
1116

1117
    char *pSec = strrchr(fname, '.');
9,050✔
1118
    if (!pSec) {
9,050!
1119
      continue;
×
1120
    }
1121
    char *pIter = pSec;
9,050✔
1122
    bool  isSec = true;
9,050✔
1123
    while (*(++pIter)) {
18,100✔
1124
      if (!isdigit(*pIter)) {
9,050!
1125
        isSec = false;
×
1126
        break;
×
1127
      }
1128
    }
1129
    if (!isSec) {
9,050!
1130
      continue;
×
1131
    }
1132

1133
    int64_t fileSec = 0;
9,050✔
1134
    if ((code = taosStr2int64(pSec + 1, &fileSec)) != 0) {
9,050!
1135
      uWarn("%s:%d failed to convert %s to int64 since %s", __func__, __LINE__, pSec + 1, tstrerror(code));
×
1136
      continue;
×
1137
    }
1138
    if (fileSec <= 100) {
9,050!
1139
      continue;
9,050✔
1140
    }
1141

1142
    char fullName[PATH_MAX] = {0};
×
1143
    snprintf(fullName, sizeof(fullName), "%s%s%s", tsLogDir, TD_DIRSEP, fname);
×
1144

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

1151
    int64_t inactiveSec = taosGetTimestampMs() / 1000 - mtime;
×
1152

1153
    if (inactiveSec < LOG_INACTIVE_TIME) {
×
1154
      continue;
×
1155
    }
1156

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

1169
  if (tsLogKeepDays != 0) {
7,860✔
1170
    taosRemoveOldFiles(tsLogDir, abs(tsLogKeepDays));
10✔
1171
  }
1172
_exit:
7,850✔
1173
  taosWUnLockLatch(&tsLogRotateLatch);
7,860✔
1174
  atomic_store_8(&tsLogRotateRunning, 0);
7,860✔
1175
  taosMemFreeClear(filePrefix);
7,860!
1176
  return NULL;
7,860✔
1177
}
1178

1179
static void *taosAsyncOutputLog(void *param) {
23,361✔
1180
  SLogBuff *pLogBuf = (SLogBuff *)tsLogObj.logHandle;
23,361✔
1181
  SLogBuff *pSlowBuf = (SLogBuff *)tsLogObj.slowHandle;
23,361✔
1182

1183
  setThreadName("log");
23,361✔
1184
  int32_t count = 0;
23,361✔
1185
  int32_t updateCron = 0;
23,361✔
1186
  int32_t writeInterval = 0;
23,361✔
1187
  int64_t lastCheckSec = taosGetTimestampMs() / 1000 - (LOG_ROTATE_INTERVAL - LOG_ROTATE_BOOT);
23,361✔
1188

1189
  while (1) {
14,118,138✔
1190
    if (pSlowBuf) {
14,141,499✔
1191
      writeInterval = TMIN(pLogBuf->writeInterval, pSlowBuf->writeInterval);
14,133,147✔
1192
    } else {
1193
      writeInterval = pLogBuf->writeInterval;
8,352✔
1194
    }
1195
    count += writeInterval;
14,141,499✔
1196
    updateCron++;
14,141,499✔
1197
    taosMsleep(writeInterval);
14,141,499✔
1198
    if (count > 1000) {
14,141,490✔
1199
      TAOS_UNUSED(osUpdate());
337,916✔
1200
      count = 0;
337,916✔
1201
    }
1202

1203
    // Polling the buffer
1204
    taosWriteLog(pLogBuf);
14,141,490✔
1205
    if (pSlowBuf) taosWriteSlowLog(pSlowBuf);
14,141,490✔
1206

1207
    if (pLogBuf->stop || (pSlowBuf && pSlowBuf->stop)) {
14,141,490!
1208
      pLogBuf->lastDuration = LOG_MAX_WAIT_MSEC;
23,352✔
1209
      taosWriteLog(pLogBuf);
23,352✔
1210
      if (pSlowBuf) taosWriteSlowLog(pSlowBuf);
23,352✔
1211
      break;
23,352✔
1212
    }
1213

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

1238
  return NULL;
23,352✔
1239
}
1240

1241
bool taosAssertDebug(bool condition, const char *file, int32_t line, bool core, const char *format, ...) {
2✔
1242
  if (condition) return false;
2✔
1243

1244
  const char *flags = "UTL FATAL ";
1✔
1245
  ELogLevel   level = DEBUG_FATAL;
1✔
1246
  int32_t     dflag = 255;  // tsLogEmbedded ? 255 : uDebugFlag
1✔
1247
  char        buffer[LOG_MAX_LINE_BUFFER_SIZE];
1248
  int32_t     len = taosBuildLogHead(buffer, flags);
1✔
1249

1250
  va_list argpointer;
1251
  va_start(argpointer, format);
1✔
1252
  len = len + vsnprintf(buffer + len, LOG_MAX_LINE_BUFFER_SIZE - len, format, argpointer);
1✔
1253
  va_end(argpointer);
1✔
1254
  buffer[len++] = '\n';
1✔
1255
  buffer[len] = 0;
1✔
1256
  taosPrintLogImp(1, 255, buffer, len);
1✔
1257

1258
  taosPrintLog(flags, level, dflag, "tAssert at file %s:%d exit:%d", file, line, tsAssert);
1✔
1259
#ifndef TD_ASTRA
1260
  taosPrintTrace(flags, level, dflag, -1);
17!
1261
#endif
1262
  if (tsAssert || core) {
1!
1263
    taosCloseLog();
×
1264
    taosMsleep(300);
×
1265

1266
#ifdef NDEBUG
1267
    abort();
1268
#else
1269
    assert(0);
×
1270
#endif
1271
  }
1272

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

1283
  if (pMsg && msgLen > 0) {
2!
1284
    snprintf(filepath, sizeof(filepath), "%s%s.%sCrashLog", tsLogDir, TD_DIRSEP, nodeType);
1✔
1285

1286
    pFile = taosOpenFile(filepath, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_APPEND);
1✔
1287
    if (pFile == NULL) {
1!
1288
      taosPrintLog(flags, level, dflag, "failed to open file:%s since %s", filepath, terrstr());
×
1289
      goto _return;
×
1290
    }
1291

1292
    if (taosLockFile(pFile) < 0) {
1!
1293
      taosPrintLog(flags, level, dflag, "failed to lock file:%s since %s", filepath, terrstr());
×
1294
      goto _return;
×
1295
    }
1296

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

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

1313
    TAOS_UNUSED(taosUnLockFile(pFile));
1✔
1314
  }
1315

1316
_return:
1✔
1317

1318
  if (pFile) (void)taosCloseFile(&pFile);
2✔
1319

1320
  taosPrintLog(flags, level, dflag, "crash signal is %d", signum);
2✔
1321

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

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

1355
crashBasicInfo gCrashBasicInfo = {0};
1356

1357
void setCrashWriterStatus(int8_t status) { atomic_store_8(&gCrashBasicInfo.status, status); }
2✔
1358
bool reportThreadSetQuit() {
×
1359
  CrashStatus status =
×
1360
      atomic_val_compare_exchange_8(&gCrashBasicInfo.status, CRASH_LOG_WRITER_INIT, CRASH_LOG_WRITER_QUIT);
×
1361
  if (status == CRASH_LOG_WRITER_INIT) {
×
1362
    return true;
×
1363
  } else {
1364
    return false;
×
1365
  }
1366
}
1367

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

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

1411
void checkAndPrepareCrashInfo() {
1✔
1412
  return checkWriteCrashLogToFileInNewThead();
1✔
1413
}
1414

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

1426
void writeCrashLogToFile(int signum, void *sigInfo, char *nodeType, int64_t clusterId, int64_t startTime) {
2✔
1427
  if (gCrashBasicInfo.reportThread == taosGetSelfPthreadId()) {
2✔
1428
    return;
1✔
1429
  }
1430
  if (setReportThreadWait()) {
1!
1431
    gCrashBasicInfo.clusterId = clusterId;
1✔
1432
    gCrashBasicInfo.startTime = startTime;
1✔
1433
    gCrashBasicInfo.nodeType = nodeType;
1✔
1434
    gCrashBasicInfo.signum = signum;
1✔
1435
    gCrashBasicInfo.sigInfo = sigInfo;
1✔
1436
    TAOS_UNUSED(tsem_wait(&gCrashBasicInfo.sem));
1✔
1437
  }
1438
}
1439

1440
void taosReadCrashInfo(char *filepath, char **pMsg, int64_t *pMsgLen, TdFilePtr *pFd) {
2✔
1441
  const char *flags = "UTL FATAL ";
2✔
1442
  ELogLevel   level = DEBUG_FATAL;
2✔
1443
  int32_t     dflag = 255;
2✔
1444
  TdFilePtr   pFile = NULL;
2✔
1445
  bool        truncateFile = false;
2✔
1446
  char       *buf = NULL;
2✔
1447

1448
  if (NULL == *pFd) {
2!
1449
    int64_t filesize = 0;
2✔
1450
    if (taosStatFile(filepath, &filesize, NULL, NULL) < 0) {
2!
1451
      if (TAOS_SYSTEM_ERROR(ENOENT) == terrno) {
×
1452
        return;
×
1453
      }
1454

1455
      taosPrintLog(flags, level, dflag, "failed to stat file:%s since %s", filepath, terrstr());
×
1456
      return;
×
1457
    }
1458

1459
    if (filesize <= 0) {
2!
1460
      return;
×
1461
    }
1462

1463
    pFile = taosOpenFile(filepath, TD_FILE_READ | TD_FILE_WRITE);
2✔
1464
    if (pFile == NULL) {
2!
1465
      if (ENOENT == ERRNO) {
×
1466
        return;
×
1467
      }
1468

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

1473
    TAOS_UNUSED(taosLockFile(pFile));
2✔
1474
  } else {
1475
    pFile = *pFd;
×
1476
  }
1477

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

1489
  buf = taosMemoryMalloc(msgLen);
2!
1490
  if (NULL == buf) {
2!
1491
    taosPrintLog(flags, level, dflag, "failed to malloc buf, size:%" PRId64, msgLen);
×
1492
    goto _return;
×
1493
  }
1494

1495
  readSize = taosReadFile(pFile, buf, msgLen);
2✔
1496
  if (msgLen != readSize) {
2✔
1497
    truncateFile = true;
1✔
1498
    taosPrintLog(flags, level, dflag, "failed to read file:%s,%p wlen:%" PRId64 " tlen:%" PRId64 " since %s", filepath,
1✔
1499
                 pFile, readSize, msgLen, terrstr());
1500
    goto _return;
1✔
1501
  }
1502

1503
  *pMsg = buf;
1✔
1504
  *pMsgLen = msgLen;
1✔
1505
  *pFd = pFile;
1✔
1506

1507
  return;
1✔
1508

1509
_return:
1✔
1510

1511
  if (truncateFile) {
1!
1512
    TAOS_UNUSED(taosFtruncateFile(pFile, 0));
1✔
1513
  }
1514
  TAOS_UNUSED(taosUnLockFile(pFile));
1✔
1515
  TAOS_UNUSED(taosCloseFile(&pFile));
1✔
1516
  taosMemoryFree(buf);
1!
1517

1518
  *pMsg = NULL;
1✔
1519
  *pMsgLen = 0;
1✔
1520
  *pFd = NULL;
1✔
1521
}
1522

1523
void taosReleaseCrashLogFile(TdFilePtr pFile, bool truncateFile) {
1✔
1524
  if (truncateFile) {
1!
1525
    TAOS_UNUSED(taosFtruncateFile(pFile, 0));
1✔
1526
  }
1527

1528
  TAOS_UNUSED(taosUnLockFile(pFile));
1✔
1529
  TAOS_UNUSED(taosCloseFile(&pFile));
1✔
1530
}
1✔
1531
#endif // USE_REPORT
1532

1533
#ifdef NDEBUG
1534
bool taosAssertRelease(bool condition) {
1535
  if (condition) return false;
1536

1537
  const char *flags = "UTL FATAL ";
1538
  ELogLevel   level = DEBUG_FATAL;
1539
  int32_t     dflag = 255;  // tsLogEmbedded ? 255 : uDebugFlag
1540

1541
  taosPrintLog(flags, level, dflag, "tAssert called in release mode, exit:%d", tsAssert);
1542
  taosPrintTrace(flags, level, dflag, 0);
1543

1544
  if (tsAssert) {
1545
    taosMsleep(300);
1546
    abort();
1547
  }
1548

1549
  return true;
1550
}
1551
#endif
1552

1553
#define NUM_BASE 100
1554
#define DIGIT_LENGTH 2
1555
#define MAX_DIGITS 24
1556

1557
char* u64toaFastLut(uint64_t val, char* buf) {
5✔
1558
  // Look-up table for 2-digit numbers
1559
  static const char* lut =
1560
      "0001020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455"
1561
      "5657585960616263646566676869707172737475767778798081828384858687888990919293949596979899";
1562

1563
  char  temp[MAX_DIGITS];
1564
  char* p = temp + tListLen(temp);
5✔
1565

1566
  // Process the digits greater than or equal to 100
1567
  while (val >= NUM_BASE) {
11✔
1568
    // Get the last 2 digits from the look-up table and add to the buffer
1569
    p -= DIGIT_LENGTH;
6✔
1570
    strncpy(p, lut + (val % NUM_BASE) * DIGIT_LENGTH, DIGIT_LENGTH);
6✔
1571
    val /= NUM_BASE;
6✔
1572
  }
1573

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

1585
  int64_t len = temp + tListLen(temp) - p;
5✔
1586
  if (len > 0) {
5✔
1587
    memcpy(buf, p, len);
4✔
1588
  } else {
1589
    buf[0] = '0';
1✔
1590
    len = 1;
1✔
1591
  }
1592
  buf[len] = '\0';
5✔
1593

1594
  return buf + len;
5✔
1595
}
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