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

taosdata / TDengine / #3558

17 Dec 2024 06:05AM UTC coverage: 59.778% (+1.6%) from 58.204%
#3558

push

travis-ci

web-flow
Merge pull request #29179 from taosdata/merge/mainto3.0

merge: form main to 3.0 branch

132787 of 287595 branches covered (46.17%)

Branch coverage included in aggregate %.

104 of 191 new or added lines in 5 files covered. (54.45%)

6085 existing lines in 168 files now uncovered.

209348 of 284746 relevant lines covered (73.52%)

8164844.48 hits per line

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

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

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

32
#define LOG_FILE_DAY_LEN 64
33

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

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

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

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

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

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

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

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

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

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

142
int32_t tqClientDebugFlag = 131;
143

144
int64_t dbgEmptyW = 0;
145
int64_t dbgWN = 0;
146
int64_t dbgSmallWN = 0;
147
int64_t dbgBigWN = 0;
148
int64_t dbgWSize = 0;
149

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

158
static int32_t taosStartLog() {
5,879✔
159
  TdThreadAttr threadAttr;
160
  (void)taosThreadAttrInit(&threadAttr);
5,879✔
161
  if (taosThreadCreate(&(tsLogObj.logHandle->asyncThread), &threadAttr, taosAsyncOutputLog, tsLogObj.logHandle) != 0) {
5,879!
162
    return terrno;
×
163
  }
164
  (void)taosThreadAttrDestroy(&threadAttr);
5,879✔
165
  return 0;
5,879✔
166
}
167

168
static int32_t getDay(char *buf, int32_t bufSize) {
1,976✔
169
  time_t  t;
170
  int32_t code = taosTime(&t);
1,976✔
171
  if (code != 0) {
1,976!
172
    return code;
×
173
  }
174
  struct tm tmInfo;
175
  if (taosLocalTime(&t, &tmInfo, buf, bufSize, NULL) != NULL) {
1,976!
176
    TAOS_UNUSED(taosStrfTime(buf, bufSize, "%Y-%m-%d", &tmInfo));
1,976✔
177
  }
178
  return 0;
1,976✔
179
}
180

181
static void getFullPathName(char *fullName, const char *logName) {
7,855✔
182
  if (strlen(tsLogDir) != 0) {
7,855!
183
    char lastC = tsLogDir[strlen(tsLogDir) - 1];
7,855✔
184
    if (lastC == '\\' || lastC == '/') {
7,855!
185
      snprintf(fullName, PATH_MAX,
551✔
186
               "%s"
187
               "%s",
188
               tsLogDir, logName);
189
    } else {
190
      snprintf(fullName, PATH_MAX, "%s" TD_DIRSEP "%s", tsLogDir, logName);
7,304✔
191
    }
192
  } else {
193
    snprintf(fullName, PATH_MAX, "%s", logName);
×
194
  }
195
}
7,855✔
196

197
int32_t taosInitSlowLog() {
1,976✔
198
  char logFileName[64] = {0};
1,976✔
199
#ifdef CUS_PROMPT
200
  (void)snprintf(logFileName, 64, "%sSlowLog", CUS_PROMPT);
201
#else
202
  (void)snprintf(logFileName, 64, "taosSlowLog");
1,976✔
203
#endif
204

205
  getFullPathName(tsLogObj.slowLogName, logFileName);
1,976✔
206

207
  char    name[PATH_MAX + TD_TIME_STR_LEN] = {0};
1,976✔
208
  char    day[TD_TIME_STR_LEN] = {0};
1,976✔
209
  int32_t code = getDay(day, sizeof(day));
1,976✔
210
  if (code != 0) {
1,976!
211
    (void)printf("failed to get day, reason:%s\n", tstrerror(code));
×
212
    return code;
×
213
  }
214
  (void)snprintf(name, PATH_MAX + TD_TIME_STR_LEN, "%s.%s", tsLogObj.slowLogName, day);
1,976✔
215

216
  tsLogObj.timestampToday = taosGetTimestampToday(TSDB_TIME_PRECISION_SECONDS, NULL);
1,976✔
217
  tsLogObj.slowHandle = taosLogBuffNew(LOG_SLOW_BUF_SIZE);
1,976✔
218
  if (tsLogObj.slowHandle == NULL) return terrno;
1,976!
219

220
  TAOS_UNUSED(taosUmaskFile(0));
1,976✔
221
  tsLogObj.slowHandle->pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_APPEND);
1,976✔
222
  if (tsLogObj.slowHandle->pFile == NULL) {
1,976!
223
    (void)printf("\nfailed to open slow log file:%s, reason:%s\n", name, strerror(errno));
×
224
    return terrno;
×
225
  }
226

227
  return 0;
1,976✔
228
}
229

230
int32_t taosInitLogOutput(const char **ppLogName) {
5,863✔
231
  const char *pLog = tsLogOutput;
5,863✔
232
  const char *pLogName = NULL;
5,863✔
233
  if (pLog) {
5,863✔
234
    if (!tIsValidFilePath(pLog, NULL)) {
2✔
235
      fprintf(stderr, "invalid log output destination:%s, contains illegal char\n", pLog);
1✔
236
      return TSDB_CODE_INVALID_CFG;
1✔
237
    }
238
    if (0 == strcasecmp(pLog, "stdout")) {
1!
239
      tsLogObj.outputType = LOG_OUTPUT_STDOUT;
×
240
      if (ppLogName) *ppLogName = pLog;
×
241
      return 0;
×
242
    }
243
    if (0 == strcasecmp(pLog, "stderr")) {
1!
244
      tsLogObj.outputType = LOG_OUTPUT_STDERR;
×
245
      if (ppLogName) *ppLogName = pLog;
×
246
      return 0;
×
247
    }
248
    if (0 == strcasecmp(pLog, "/dev/null")) {
1!
249
      tsLogObj.outputType = LOG_OUTPUT_NULL;
×
250
      if (ppLogName) *ppLogName = pLog;
×
251
      return 0;
×
252
    }
253
    int32_t len = strlen(pLog);
1✔
254
    if (len < 1) {
1!
255
      fprintf(stderr, "invalid log output destination:%s, should not be empty\n", pLog);
×
256
      return TSDB_CODE_INVALID_CFG;
×
257
    }
258
    const char *p = pLog + (len - 1);
1✔
259
    if (*p == '/' || *p == '\\') {
1!
UNCOV
260
      return 0;
×
261
    }
262

263
    if ((p = strrchr(pLog, '/')) || (p = strrchr(pLog, '\\'))) {
1!
264
      pLogName = p + 1;
1✔
265
    } else {
266
      pLogName = pLog;
×
267
    }
268
    if (strcmp(pLogName, ".") == 0 || strcmp(pLogName, "..") == 0) {
1!
269
      fprintf(stderr, "invalid log output destination:%s\n", pLog);
×
270
      return TSDB_CODE_INVALID_CFG;
×
271
    }
272

273
    if (!tIsValidFileName(pLogName, NULL)) {
1!
274
      fprintf(stderr, "invalid log output destination:%s, contains illegal char\n", pLog);
×
275
      return TSDB_CODE_INVALID_CFG;
×
276
    }
277
    if (ppLogName) *ppLogName = pLogName;
1!
278
  }
279
  return 0;
5,862✔
280
}
281

282
int32_t taosInitLog(const char *logName, int32_t maxFiles, bool tsc) {
6,407✔
283
  if (atomic_val_compare_exchange_8(&tsLogInited, 0, 1) != 0) return 0;
6,407✔
284
  int32_t code = osUpdate();
5,879✔
285
  if (code != 0) {
5,879!
286
    uError("failed to update os info, reason:%s", tstrerror(code));
×
287
  }
288

289
  if (tsLogObj.outputType == LOG_OUTPUT_STDOUT || tsLogObj.outputType == LOG_OUTPUT_STDERR ||
5,879!
290
      tsLogObj.outputType == LOG_OUTPUT_NULL) {
5,879!
291
    return 0;
×
292
  }
293

294
  TAOS_CHECK_RETURN(taosInitNormalLog(logName, maxFiles));
5,879!
295
  if (tsc) {
5,879✔
296
    TAOS_CHECK_RETURN(taosInitSlowLog());
1,976!
297
  }
298
  TAOS_CHECK_RETURN(taosStartLog());
5,879!
299
  return 0;
5,879✔
300
}
301

302
void taosSetNoNewFile() { tsLogObj.openInProgress = 1; }
1✔
303

304
static void taosStopLog() {
5,872✔
305
  if (tsLogObj.logHandle) {
5,872✔
306
    tsLogObj.logHandle->stop = 1;
5,871✔
307
  }
308
  if (tsLogObj.slowHandle) {
5,872✔
309
    tsLogObj.slowHandle->stop = 1;
1,975✔
310
  }
311
}
5,872✔
312

313
void taosCloseLog() {
5,872✔
314
  taosStopLog();
5,872✔
315

316
  if (tsLogObj.logHandle != NULL && taosCheckPthreadValid(tsLogObj.logHandle->asyncThread)) {
5,872!
317
    (void)taosThreadJoin(tsLogObj.logHandle->asyncThread, NULL);
5,871✔
318
    taosThreadClear(&tsLogObj.logHandle->asyncThread);
5,871✔
319
  }
320

321
  if (tsLogObj.slowHandle != NULL) {
5,872✔
322
    (void)taosThreadMutexDestroy(&tsLogObj.slowHandle->buffMutex);
1,975✔
323
    (void)taosCloseFile(&tsLogObj.slowHandle->pFile);
1,975✔
324
    taosMemoryFreeClear(tsLogObj.slowHandle->buffer);
1,975!
325
    taosMemoryFreeClear(tsLogObj.slowHandle);
1,975!
326
  }
327

328
  if (tsLogObj.logHandle != NULL) {
5,872✔
329
    tsLogInited = 0;
5,871✔
330

331
    (void)taosThreadMutexDestroy(&tsLogObj.logHandle->buffMutex);
5,871✔
332
    (void)taosCloseFile(&tsLogObj.logHandle->pFile);
5,871✔
333
    taosMemoryFreeClear(tsLogObj.logHandle->buffer);
5,871!
334
    (void)taosThreadMutexDestroy(&tsLogObj.logMutex);
5,871✔
335
    taosMemoryFreeClear(tsLogObj.logHandle);
5,871!
336
    tsLogObj.logHandle = NULL;
5,871✔
337
  }
338
  taosMemoryFreeClear(tsLogOutput);
5,872!
339
}
5,872✔
340

341
static bool taosLockLogFile(TdFilePtr pFile) {
7,005✔
342
  if (pFile == NULL) return false;
7,005!
343

344
  if (tsLogObj.fileNum > 1) {
7,005✔
345
    int32_t ret = taosLockFile(pFile);
2,615✔
346
    if (ret == 0) {
2,615✔
347
      return true;
2,134✔
348
    }
349
  }
350

351
  return false;
4,871✔
352
}
353

354
static void taosUnLockLogFile(TdFilePtr pFile) {
645✔
355
  if (pFile == NULL) return;
645!
356

357
  if (tsLogObj.fileNum > 1) {
645!
358
    int32_t code = taosUnLockFile(pFile);
645✔
359
    if (code != 0) {
645!
360
      TAOS_UNUSED(printf("failed to unlock log file:%p, reason:%s\n", pFile, tstrerror(code)));
×
361
    }
362
  }
363
}
364

365
static void taosReserveOldLog(char *oldName, char *keepName) {
1✔
366
  if (tsLogKeepDays <= 0) {
1!
367
    keepName[0] = 0;
1✔
368
    return;
1✔
369
  }
370

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

385
static void taosKeepOldLog(char *oldName) {
2✔
386
  if (oldName[0] != 0) {
2!
387
    char compressFileName[PATH_MAX + 20];
388
    snprintf(compressFileName, PATH_MAX + 20, "%s.gz", oldName);
2✔
389
    if (taosCompressFile(oldName, compressFileName) == 0) {
2!
390
      int32_t code = taosRemoveFile(oldName);
2✔
391
      if (code != 0) {
2!
392
        TAOS_UNUSED(printf("failed to remove file:%s, reason:%s\n", oldName, tstrerror(code)));
×
393
      }
394
    }
395
  }
396
}
2✔
397
typedef struct {
398
  TdFilePtr pOldFile;
399
  char      keepName[PATH_MAX + 20];
400
} OldFileKeeper;
401
static OldFileKeeper *taosOpenNewFile() {
1✔
402
  char keepName[PATH_MAX + 20];
403
  TAOS_UNUSED(snprintf(keepName, sizeof(keepName), "%s.%d", tsLogObj.logName, tsLogObj.flag));
1✔
404

405
  tsLogObj.flag ^= 1;
1✔
406
  tsLogObj.lines = 0;
1✔
407
  char name[PATH_MAX + 20];
408
  TAOS_UNUSED(snprintf(name, sizeof(name), "%s.%d", tsLogObj.logName, tsLogObj.flag));
1✔
409

410
  TAOS_UNUSED(taosUmaskFile(0));
1✔
411

412
  TdFilePtr pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC);
1✔
413
  if (pFile == NULL) {
1!
414
    tsLogObj.openInProgress = 0;
×
415
    tsLogObj.lines = tsNumOfLogLines - 1000;
×
416
    uError("open new log file fail! reason:%s, reuse lastlog", strerror(errno));
×
417
    return NULL;
×
418
  }
419

420
  TAOS_UNUSED(taosLockLogFile(pFile));
1✔
421
  if (taosLSeekFile(pFile, 0, SEEK_SET) < 0) {
1!
422
    uWarn("failed to seek file:%s, reason:%s", name, tstrerror(terrno));
×
423
  }
424

425
  TdFilePtr pOldFile = tsLogObj.logHandle->pFile;
1✔
426
  tsLogObj.logHandle->pFile = pFile;
1✔
427
  tsLogObj.lines = 0;
1✔
428
  tsLogObj.openInProgress = 0;
1✔
429
  OldFileKeeper *oldFileKeeper = taosMemoryMalloc(sizeof(OldFileKeeper));
1!
430
  if (oldFileKeeper == NULL) {
1!
431
    uError("create old log keep info faild! mem is not enough.");
×
432
    return NULL;
×
433
  }
434
  oldFileKeeper->pOldFile = pOldFile;
1✔
435
  taosReserveOldLog(keepName, oldFileKeeper->keepName);
1✔
436

437
  uInfo("   new log file:%d is opened", tsLogObj.flag);
1!
438
  uInfo("==================================");
1!
439
  return oldFileKeeper;
1✔
440
}
441

442
static void *taosThreadToCloseOldFile(void *param) {
1✔
443
  if (!param) return NULL;
1!
444
  OldFileKeeper *oldFileKeeper = (OldFileKeeper *)param;
1✔
445
  taosSsleep(20);
1✔
446
  taosWLockLatch(&tsLogRotateLatch);
×
447
  taosCloseLogByFd(oldFileKeeper->pOldFile);
×
448
  taosKeepOldLog(oldFileKeeper->keepName);
×
449
  taosMemoryFree(oldFileKeeper);
×
450
  if (tsLogKeepDays > 0) {
×
451
    taosRemoveOldFiles(tsLogDir, tsLogKeepDays);
×
452
  }
453
  taosWUnLockLatch(&tsLogRotateLatch);
×
454
  return NULL;
×
455
}
456

457
static int32_t taosOpenNewLogFile() {
1✔
458
  (void)taosThreadMutexLock(&tsLogObj.logMutex);
1✔
459

460
  if (tsLogObj.lines > tsNumOfLogLines && tsLogObj.openInProgress == 0) {
1!
461
    tsLogObj.openInProgress = 1;
1✔
462

463
    uInfo("open new log file ......");
1!
464
    TdThread     thread;
465
    TdThreadAttr attr;
466
    (void)taosThreadAttrInit(&attr);
1✔
467
    (void)taosThreadAttrSetDetachState(&attr, PTHREAD_CREATE_DETACHED);
1✔
468

469
    OldFileKeeper *oldFileKeeper = taosOpenNewFile();
1✔
470
    if (!oldFileKeeper) {
1!
471
      TAOS_UNUSED(taosThreadMutexUnlock(&tsLogObj.logMutex));
×
472
      return terrno;
×
473
    }
474
    if (taosThreadCreate(&thread, &attr, taosThreadToCloseOldFile, oldFileKeeper) != 0) {
1!
475
      uError("failed to create thread to close old log file");
×
476
      taosMemoryFreeClear(oldFileKeeper);
×
477
    }
478
    (void)taosThreadAttrDestroy(&attr);
1✔
479
  }
480

481
  (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
1✔
482

483
  return 0;
1✔
484
}
485

486
static void taosOpenNewSlowLogFile() {
×
487
  (void)taosThreadMutexLock(&tsLogObj.logMutex);
×
488
  int64_t delta = taosGetTimestampSec() - tsLogObj.timestampToday;
×
489
  if (delta >= 0 && delta < 86400) {
×
490
    uInfo("timestampToday is already equal to today, no need to open new slow log file");
×
491
    (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
×
492
    return;
×
493
  }
494

495
  for (int32_t i = 1; atomic_val_compare_exchange_32(&tsLogObj.slowHandle->lock, 0, 1) == 1; ++i) {
×
496
    if (i % 1000 == 0) {
×
497
      TAOS_UNUSED(sched_yield());
×
498
    }
499
  }
500
  tsLogObj.slowHandle->lastDuration = LOG_MAX_WAIT_MSEC;  // force write
×
501
  taosWriteLog(tsLogObj.slowHandle);
×
502
  atomic_store_32(&tsLogObj.slowHandle->lock, 0);
×
503

504
  char    day[TD_TIME_STR_LEN] = {0};
×
505
  int32_t code = getDay(day, sizeof(day));
×
506
  if (code != 0) {
×
507
    uError("failed to get day, reason:%s", tstrerror(code));
×
508
    (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
×
509
    return;
×
510
  }
511
  TdFilePtr pFile = NULL;
×
512
  char      name[PATH_MAX + TD_TIME_STR_LEN] = {0};
×
513
  (void)snprintf(name, PATH_MAX + TD_TIME_STR_LEN, "%s.%s", tsLogObj.slowLogName, day);
×
514
  pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_APPEND);
×
515
  if (pFile == NULL) {
×
516
    uError("open new log file fail! reason:%s, reuse lastlog", strerror(errno));
×
517
    (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
×
518
    return;
×
519
  }
520

521
  TdFilePtr pOldFile = tsLogObj.slowHandle->pFile;
×
522
  tsLogObj.slowHandle->pFile = pFile;
×
523
  (void)taosCloseFile(&pOldFile);
×
524
  tsLogObj.timestampToday = taosGetTimestampToday(TSDB_TIME_PRECISION_SECONDS, NULL);
×
525
  (void)taosThreadMutexUnlock(&tsLogObj.logMutex);
×
526
}
527

528
void taosResetLog() {
1✔
529
  // force create a new log file
530
  tsLogObj.lines = tsNumOfLogLines + 10;
1✔
531

532
  if (tsLogObj.logHandle) {
1!
533
    int32_t code = taosOpenNewLogFile();
1✔
534
    if (code != 0) {
1!
535
      uError("failed to open new log file, reason:%s", tstrerror(code));
×
536
    }
537
    uInfo("==================================");
1!
538
    uInfo("   reset log file ");
1!
539
  }
540
}
1✔
541

542
static bool taosCheckFileIsOpen(char *logFileName) {
3,938✔
543
  TdFilePtr pFile = taosOpenFile(logFileName, TD_FILE_WRITE);
3,938✔
544
  if (pFile == NULL) {
3,938✔
545
    if (lastErrorIsFileNotExist()) {
2,813!
546
      return false;
2,813✔
547
    } else {
548
      printf("\nfailed to open log file:%s, reason:%s\n", logFileName, strerror(errno));
×
549
      return true;
×
550
    }
551
  }
552

553
  if (taosLockLogFile(pFile)) {
1,125✔
554
    taosUnLockLogFile(pFile);
645✔
555
    (void)taosCloseFile(&pFile);
645✔
556
    return false;
645✔
557
  } else {
558
    (void)taosCloseFile(&pFile);
480✔
559
    return true;
480✔
560
  }
561
}
562

563
static void decideLogFileName(const char *fn, int32_t maxFileNum) {
5,879✔
564
  tsLogObj.fileNum = maxFileNum;
5,879✔
565
  if (tsLogObj.fileNum > 1) {
5,879✔
566
    for (int32_t i = 0; i < tsLogObj.fileNum; i++) {
1,970✔
567
      char fileName[PATH_MAX + 10];
568

569
      (void)snprintf(fileName, PATH_MAX + 10, "%s%d.0", fn, i);
1,969✔
570
      bool file1open = taosCheckFileIsOpen(fileName);
1,969✔
571

572
      (void)snprintf(fileName, PATH_MAX + 10, "%s%d.1", fn, i);
1,969✔
573
      bool file2open = taosCheckFileIsOpen(fileName);
1,969✔
574

575
      if (!file1open && !file2open) {
1,969!
576
        (void)snprintf(tsLogObj.logName, PATH_MAX, "%s%d", fn, i);
1,489✔
577
        return;
1,489✔
578
      }
579
    }
580
  }
581

582
  if (strlen(fn) < PATH_MAX) {
4,390!
583
    tstrncpy(tsLogObj.logName, fn, PATH_MAX);
4,390✔
584
  }
585
}
586

587
static void decideLogFileNameFlag() {
5,879✔
588
  char    name[PATH_MAX] = "\0";
5,879✔
589
  int64_t logstat0_mtime = 0;
5,879✔
590
  int64_t logstat1_mtime = 0;
5,879✔
591
  bool    log0Exist = false;
5,879✔
592
  bool    log1Exist = false;
5,879✔
593

594
  int32_t logNameLen = strlen(tsLogObj.logName) + 2;
5,879✔
595
  if (logNameLen < PATH_MAX) {
5,879!
596
    TAOS_UNUSED(snprintf(name, PATH_MAX, "%s%s", tsLogObj.logName, ".0"));
5,879✔
597
    log0Exist = taosStatFile(name, NULL, &logstat0_mtime, NULL) == 0;
5,879✔
598
    name[logNameLen - 1] = '1';
5,879✔
599
    log1Exist = taosStatFile(name, NULL, &logstat1_mtime, NULL) == 0;
5,879✔
600
  }
601

602
  // if none of the log files exist, open 0, if both exists, open the old one
603
  if (!log0Exist && !log1Exist) {
5,879!
604
    tsLogObj.flag = 0;
4,506✔
605
  } else if (!log1Exist) {
1,373!
606
    tsLogObj.flag = 0;
1,373✔
607
  } else if (!log0Exist) {
×
608
    tsLogObj.flag = 1;
×
609
  } else {
610
    tsLogObj.flag = (logstat0_mtime > logstat1_mtime) ? 0 : 1;
×
611
  }
612
}
5,879✔
613

614
static void processLogFileName(const char *logName, int32_t maxFileNum) {
5,879✔
615
  char fullName[PATH_MAX] = {0};
5,879✔
616
  getFullPathName(fullName, logName);
5,879✔
617
  decideLogFileName(fullName, maxFileNum);
5,879✔
618
  decideLogFileNameFlag();
5,879✔
619
}
5,879✔
620

621
static int32_t taosInitNormalLog(const char *logName, int32_t maxFileNum) {
5,879✔
622
#ifdef WINDOWS_STASH
623
  /*
624
   * always set maxFileNum to 1
625
   * means client log filename is unique in windows
626
   */
627
  maxFileNum = 1;
628
#endif
629

630
  processLogFileName(logName, maxFileNum);
5,879✔
631

632
  int32_t logNameLen = strlen(tsLogObj.logName) + 2;  // logName + ".0" or ".1"
5,879✔
633

634
  if (logNameLen < 0 || logNameLen >= PATH_MAX) {
5,879!
635
    uError("log name:%s is invalid since length:%d is out of range", logName, logNameLen);
×
636
    return TSDB_CODE_INVALID_CFG;
×
637
  }
638

639
  char name[PATH_MAX] = "\0";
5,879✔
640
  (void)snprintf(name, sizeof(name), "%s.%d", tsLogObj.logName, tsLogObj.flag);
5,879✔
641
  (void)taosThreadMutexInit(&tsLogObj.logMutex, NULL);
5,879✔
642

643
  TAOS_UNUSED(taosUmaskFile(0));
5,879✔
644
  tsLogObj.logHandle = taosLogBuffNew(LOG_DEFAULT_BUF_SIZE);
5,879✔
645
  if (tsLogObj.logHandle == NULL) return terrno;
5,879!
646

647
  tsLogObj.logHandle->pFile = taosOpenFile(name, TD_FILE_CREATE | TD_FILE_WRITE);
5,879✔
648
  if (tsLogObj.logHandle->pFile == NULL) {
5,879!
649
    (void)printf("\nfailed to open log file:%s, reason:%s\n", name, strerror(errno));
×
650
    return terrno;
×
651
  }
652
  TAOS_UNUSED(taosLockLogFile(tsLogObj.logHandle->pFile));
5,879✔
653

654
  // only an estimate for number of lines
655
  int64_t filesize = 0;
5,879✔
656
  if (taosFStatFile(tsLogObj.logHandle->pFile, &filesize, NULL) != 0) {
5,879!
657
    (void)printf("\nfailed to fstat log file:%s, reason:%s\n", name, strerror(errno));
×
658
    taosUnLockLogFile(tsLogObj.logHandle->pFile);
×
659
    return terrno;
×
660
  }
661
  tsLogObj.lines = (int32_t)(filesize / 60);
5,879✔
662

663
  if (taosLSeekFile(tsLogObj.logHandle->pFile, 0, SEEK_END) < 0) {
5,879!
664
    TAOS_UNUSED(printf("failed to seek to the end of log file:%s, reason:%s\n", name, tstrerror(terrno)));
×
665
    taosUnLockLogFile(tsLogObj.logHandle->pFile);
×
666
    return terrno;
×
667
  }
668

669
  (void)snprintf(name, sizeof(name), "==================================================\n");
5,879✔
670
  if (taosWriteFile(tsLogObj.logHandle->pFile, name, (uint32_t)strlen(name)) <= 0) {
5,879!
671
    TAOS_UNUSED(printf("failed to write to log file:%s, reason:%s\n", name, tstrerror(terrno)));
×
672
    taosUnLockLogFile(tsLogObj.logHandle->pFile);
×
673
    return terrno;
×
674
  }
675
  (void)snprintf(name, sizeof(name), "                new log file                      \n");
5,879✔
676
  if (taosWriteFile(tsLogObj.logHandle->pFile, name, (uint32_t)strlen(name)) <= 0) {
5,879!
677
    TAOS_UNUSED(printf("failed to write to log file:%s, reason:%s\n", name, tstrerror(terrno)));
×
678
    taosUnLockLogFile(tsLogObj.logHandle->pFile);
×
679
    return terrno;
×
680
  }
681
  (void)snprintf(name, sizeof(name), "==================================================\n");
5,879✔
682
  if (taosWriteFile(tsLogObj.logHandle->pFile, name, (uint32_t)strlen(name)) <= 0) {
5,879!
683
    TAOS_UNUSED(printf("failed to write to log file:%s, reason:%s\n", name, tstrerror(terrno)));
×
684
    taosUnLockLogFile(tsLogObj.logHandle->pFile);
×
685
    return terrno;
×
686
  }
687

688
  return 0;
5,879✔
689
}
690

691
static void taosUpdateLogNums(ELogLevel level) {
486,053,718✔
692
  switch (level) {
486,053,718!
693
    case DEBUG_ERROR:
456,815✔
694
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfErrorLogs, 1));
456,815✔
695
      break;
456,864✔
696
    case DEBUG_INFO:
8,840,167✔
697
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfInfoLogs, 1));
8,840,167✔
698
      break;
8,844,013✔
699
    case DEBUG_DEBUG:
411,854,550✔
700
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfDebugLogs, 1));
411,854,550✔
701
      break;
411,994,658✔
702
    case DEBUG_DUMP:
64,933,761✔
703
    case DEBUG_TRACE:
704
      TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfTraceLogs, 1));
64,933,761✔
705
      break;
64,942,986✔
706
    default:
×
707
      break;
×
708
  }
709
}
486,206,946✔
710

711
static inline int32_t taosBuildLogHead(char *buffer, const char *flags) {
487,798,174✔
712
  struct tm      Tm, *ptm;
713
  struct timeval timeSecs;
714

715
  TAOS_UNUSED(taosGetTimeOfDay(&timeSecs));
487,798,174✔
716
  time_t curTime = timeSecs.tv_sec;
487,686,407✔
717
  ptm = taosLocalTime(&curTime, &Tm, NULL, 0, NULL);
487,686,407✔
718
  if (ptm == NULL) {
487,976,083!
719
    uError("%s failed to get local time, code:%d", __FUNCTION__, errno);
×
720
    return 0;
×
721
  }
722
  return snprintf(buffer, LOG_MAX_STACK_LINE_BUFFER_SIZE, "%02d/%02d %02d:%02d:%02d.%06d %08" PRId64 " %s %s",
487,976,083✔
723
                  ptm->tm_mon + 1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (int32_t)timeSecs.tv_usec,
487,950,199✔
724
                  taosGetSelfPthreadId(), LOG_EDITION_FLG, flags);
725
}
726

727
static inline void taosPrintLogImp(ELogLevel level, int32_t dflag, const char *buffer, int32_t len) {
486,552,645✔
728
  if ((dflag & DEBUG_FILE) && tsLogObj.logHandle && tsLogObj.logHandle->pFile != NULL && osLogSpaceSufficient()) {
486,552,645!
729
    taosUpdateLogNums(level);
486,066,084✔
730
    if (tsAsyncLog) {
486,210,788✔
731
      TAOS_UNUSED(taosPushLogBuffer(tsLogObj.logHandle, buffer, len));
1,025,925✔
732
    } else {
733
      TAOS_UNUSED(taosWriteFile(tsLogObj.logHandle->pFile, buffer, len));
485,184,863✔
734
    }
735

736
    if (tsNumOfLogLines > 0) {
486,284,583!
737
      TAOS_UNUSED(atomic_add_fetch_32(&tsLogObj.lines, 1));
486,286,990✔
738
      if ((tsLogObj.lines > tsNumOfLogLines) && (tsLogObj.openInProgress == 0)) {
486,291,165!
739
        int32_t code = taosOpenNewLogFile();
×
740
        if (code != 0) {
×
741
          uError("failed to open new log file, reason:%s", tstrerror(code));
×
742
        }
743
      }
744
    }
745
  }
746

747
  int fd = 0;
486,738,593✔
748
  if (tsLogObj.outputType == LOG_OUTPUT_FILE) {
486,738,593!
749
    if (dflag & DEBUG_SCREEN) fd = 1;
486,738,593✔
750
  } else if (tsLogObj.outputType == LOG_OUTPUT_STDOUT) {
×
751
    fd = 1;
×
752
  } else if (tsLogObj.outputType == LOG_OUTPUT_STDERR) {
×
753
    fd = 2;
×
754
  }
755

756
  if (fd) {
486,738,593✔
757
#pragma GCC diagnostic push
758
#pragma GCC diagnostic ignored "-Wunused-result"
759
    if (write(fd, buffer, (uint32_t)len) < 0) {
8,512,238✔
760
      TAOS_UNUSED(printf("failed to write log to screen, reason:%s\n", strerror(errno)));
25,108✔
761
    }
762
#pragma GCC diagnostic pop
763
  }
764
}
486,738,563✔
765

766
/*
767
  use taosPrintLogImpl_useStackBuffer to avoid stack overflow
768

769
*/
770
static int8_t taosPrintLogImplUseStackBuffer(const char *flags, int32_t level, int32_t dflag, const char *format,
484,420,211✔
771
                                             va_list args) {
772
  char    buffer[LOG_MAX_STACK_LINE_BUFFER_SIZE];
773
  int32_t len = taosBuildLogHead(buffer, flags);
484,420,211✔
774

775
  int32_t writeLen = len + vsnprintf(buffer + len, LOG_MAX_STACK_LINE_BUFFER_SIZE - len - 1, format, args);
484,420,484✔
776
  if (writeLen > LOG_MAX_STACK_LINE_SIZE) {
484,420,484✔
777
    return 1;
1,258,101✔
778
  }
779

780
  buffer[writeLen++] = '\n';
483,162,383✔
781
  buffer[writeLen] = 0;
483,162,383✔
782

783
  taosPrintLogImp(level, dflag, buffer, writeLen);
483,162,383✔
784

785
  if (tsLogFp && level <= DEBUG_INFO) {
483,304,842✔
786
    buffer[writeLen - 1] = 0;
7,514,797✔
787
    (*tsLogFp)(taosGetTimestampMs(), level, buffer + len);
15,029,534✔
788
  }
789
  return 0;
483,305,889✔
790
}
791
static int8_t taosPrintLogImplUseHeapBuffer(const char *flags, int32_t level, int32_t dflag, const char *format,
1,258,097✔
792
                                            va_list args) {
793
  char *buffer = taosMemoryCalloc(1, LOG_MAX_LINE_BUFFER_SIZE + 1);
1,258,097!
794
  if (buffer == NULL) {
1,258,095!
795
    return 1;
×
796
  }
797
  int32_t len = taosBuildLogHead(buffer, flags);
1,258,095✔
798

799
  int32_t writeLen = len + vsnprintf(buffer + len, LOG_MAX_LINE_BUFFER_SIZE - len - 1, format, args);
1,258,114✔
800

801
  if (writeLen > LOG_MAX_LINE_SIZE) writeLen = LOG_MAX_LINE_SIZE;
1,258,114✔
802
  buffer[writeLen++] = '\n';
1,258,114✔
803
  buffer[writeLen] = 0;
1,258,114✔
804

805
  taosPrintLogImp(level, dflag, buffer, writeLen);
1,258,114✔
806

807
  if (tsLogFp && level <= DEBUG_INFO) {
1,258,116✔
808
    buffer[writeLen - 1] = 0;
60,347✔
809
    (*tsLogFp)(taosGetTimestampMs(), level, buffer + len);
120,694✔
810
  }
811
  taosMemoryFree(buffer);
1,258,116!
812
  return 0;
1,258,116✔
813
}
814
void taosPrintLog(const char *flags, int32_t level, int32_t dflag, const char *format, ...) {
484,269,305✔
815
  if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return;
484,269,305!
816

817
  va_list argpointer, argpointer_copy;
818
  va_start(argpointer, format);
484,269,305✔
819
  va_copy(argpointer_copy, argpointer);
484,269,305✔
820

821
  if (taosPrintLogImplUseStackBuffer(flags, level, dflag, format, argpointer) == 0) {
484,269,305✔
822
  } else {
823
    TAOS_UNUSED(taosPrintLogImplUseHeapBuffer(flags, level, dflag, format, argpointer_copy));
1,258,105✔
824
  }
825
  va_end(argpointer_copy);
484,564,146✔
826
  va_end(argpointer);
484,564,146✔
827
}
828

829
void taosPrintLongString(const char *flags, int32_t level, int32_t dflag, const char *format, ...) {
2,175,998✔
830
  if (!osLogSpaceSufficient()) return;
2,175,998!
831
  if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return;
2,175,997!
832

833
  char *buffer = taosMemoryMalloc(LOG_MAX_LINE_DUMP_BUFFER_SIZE);
2,175,997!
834
  if (!buffer) return;
2,175,999!
835
  int32_t len = taosBuildLogHead(buffer, flags);
2,175,999✔
836

837
  va_list argpointer;
838
  va_start(argpointer, format);
2,176,000✔
839
  len += vsnprintf(buffer + len, LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 - len, format, argpointer);
2,176,000✔
840
  va_end(argpointer);
2,176,000✔
841

842
  len = len > LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 ? LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 : len;
2,176,000✔
843
  buffer[len++] = '\n';
2,176,000✔
844
  buffer[len] = 0;
2,176,000✔
845

846
  taosPrintLogImp(level, dflag, buffer, len);
2,176,000✔
847
  taosMemoryFree(buffer);
2,176,000!
848
}
849

850
void taosPrintSlowLog(const char *format, ...) {
249✔
851
  if (!osLogSpaceSufficient()) return;
249!
852

853
  int64_t delta = taosGetTimestampSec() - tsLogObj.timestampToday;
249✔
854
  if (delta >= 86400 || delta < 0) {
249!
855
    taosOpenNewSlowLogFile();
×
856
  }
857

858
  char   *buffer = taosMemoryMalloc(LOG_MAX_LINE_DUMP_BUFFER_SIZE);
249!
859
  int32_t len = taosBuildLogHead(buffer, "");
249✔
860

861
  va_list argpointer;
862
  va_start(argpointer, format);
249✔
863
  len += vsnprintf(buffer + len, LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2 - len, format, argpointer);
249✔
864
  va_end(argpointer);
249✔
865

866
  if (len < 0 || len > LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2) {
249!
867
    len = LOG_MAX_LINE_DUMP_BUFFER_SIZE - 2;
×
868
  }
869
  buffer[len++] = '\n';
249✔
870
  buffer[len] = 0;
249✔
871

872
  TAOS_UNUSED(atomic_add_fetch_64(&tsNumOfSlowLogs, 1));
249✔
873

874
  if (tsAsyncLog) {
249!
875
    TAOS_UNUSED(taosPushLogBuffer(tsLogObj.slowHandle, buffer, len));
×
876
  } else {
877
    TAOS_UNUSED(taosWriteFile(tsLogObj.slowHandle->pFile, buffer, len));
249✔
878
  }
879

880
  taosMemoryFree(buffer);
249!
881
}
882

883
static void taosCloseLogByFd(TdFilePtr pFile) {
×
884
  if (pFile != NULL) {
×
885
    taosUnLockLogFile(pFile);
×
886
    (void)taosCloseFile(&pFile);
×
887
  }
888
}
×
889

890
static SLogBuff *taosLogBuffNew(int32_t bufSize) {
7,855✔
891
  SLogBuff *pLogBuf = NULL;
7,855✔
892

893
  pLogBuf = taosMemoryCalloc(1, sizeof(SLogBuff));
7,855!
894
  if (pLogBuf == NULL) return NULL;
7,855!
895

896
  LOG_BUF_BUFFER(pLogBuf) = taosMemoryMalloc(bufSize);
7,855!
897
  if (LOG_BUF_BUFFER(pLogBuf) == NULL) goto _err;
7,855!
898

899
  LOG_BUF_START(pLogBuf) = LOG_BUF_END(pLogBuf) = 0;
7,855✔
900
  LOG_BUF_SIZE(pLogBuf) = bufSize;
7,855✔
901
  pLogBuf->minBuffSize = bufSize / 10;
7,855✔
902
  pLogBuf->stop = 0;
7,855✔
903
  pLogBuf->writeInterval = LOG_DEFAULT_INTERVAL;
7,855✔
904
  pLogBuf->lock = 0;
7,855✔
905
  if (taosThreadMutexInit(&LOG_BUF_MUTEX(pLogBuf), NULL) < 0) goto _err;
7,855!
906
  // tsem_init(&(pLogBuf->buffNotEmpty), 0, 0);
907

908
  return pLogBuf;
7,855✔
909

910
_err:
×
911
  taosMemoryFreeClear(LOG_BUF_BUFFER(pLogBuf));
×
912
  taosMemoryFreeClear(pLogBuf);
×
913
  return NULL;
×
914
}
915

916
static void taosCopyLogBuffer(SLogBuff *pLogBuf, int32_t start, int32_t end, const char *msg, int32_t msgLen) {
1,026,036✔
917
  if (start > end) {
1,026,036✔
918
    memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, msgLen);
632✔
919
  } else {
920
    if (LOG_BUF_SIZE(pLogBuf) - end < msgLen) {
1,025,404✔
921
      memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, LOG_BUF_SIZE(pLogBuf) - end);
2✔
922
      memcpy(LOG_BUF_BUFFER(pLogBuf), msg + LOG_BUF_SIZE(pLogBuf) - end, msgLen - LOG_BUF_SIZE(pLogBuf) + end);
2✔
923
    } else {
924
      memcpy(LOG_BUF_BUFFER(pLogBuf) + end, msg, msgLen);
1,025,402✔
925
    }
926
  }
927
  LOG_BUF_END(pLogBuf) = (LOG_BUF_END(pLogBuf) + msgLen) % LOG_BUF_SIZE(pLogBuf);
1,026,036✔
928
}
1,026,036✔
929

930
static int32_t taosPushLogBuffer(SLogBuff *pLogBuf, const char *msg, int32_t msgLen) {
1,025,739✔
931
  int32_t        start = 0;
1,025,739✔
932
  int32_t        end = 0;
1,025,739✔
933
  int32_t        remainSize = 0;
1,025,739✔
934
  static int64_t lostLine = 0;
935
  char           tmpBuf[128];
936
  int32_t        tmpBufLen = 0;
1,025,739✔
937

938
  if (pLogBuf == NULL || pLogBuf->stop) return -1;
1,025,739!
939

940
  (void)taosThreadMutexLock(&LOG_BUF_MUTEX(pLogBuf));
1,025,753✔
941
  start = LOG_BUF_START(pLogBuf);
1,026,036✔
942
  end = LOG_BUF_END(pLogBuf);
1,026,036✔
943

944
  remainSize = (start > end) ? (start - end - 1) : (start + LOG_BUF_SIZE(pLogBuf) - end - 1);
1,026,036✔
945

946
  if (lostLine > 0) {
1,026,036!
947
    snprintf(tmpBuf, tListLen(tmpBuf), "...Lost %" PRId64 " lines here...\n", lostLine);
×
948
    tmpBufLen = (int32_t)strlen(tmpBuf);
×
949
  }
950

951
  if (remainSize <= msgLen || ((lostLine > 0) && (remainSize <= (msgLen + tmpBufLen)))) {
1,026,036!
952
    lostLine++;
×
953
    tsAsyncLogLostLines++;
×
954
    (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
×
955
    return -1;
×
956
  }
957

958
  if (lostLine > 0) {
1,026,036!
959
    taosCopyLogBuffer(pLogBuf, start, end, tmpBuf, tmpBufLen);
×
960
    lostLine = 0;
×
961
  }
962

963
  taosCopyLogBuffer(pLogBuf, LOG_BUF_START(pLogBuf), LOG_BUF_END(pLogBuf), msg, msgLen);
1,026,036✔
964

965
  // int32_t w = atomic_sub_fetch_32(&waitLock, 1);
966
  /*
967
  if (w <= 0 || ((remainSize - msgLen - tmpBufLen) < (LOG_BUF_SIZE(pLogBuf) * 4 /5))) {
968
    tsem_post(&(pLogBuf->buffNotEmpty));
969
    dbgPostN++;
970
  } else {
971
    dbgNoPostN++;
972
  }
973
  */
974

975
  (void)taosThreadMutexUnlock(&LOG_BUF_MUTEX(pLogBuf));
1,026,036✔
976

977
  return 0;
1,025,993✔
978
}
979

980
static int32_t taosGetLogRemainSize(SLogBuff *pLogBuf, int32_t start, int32_t end) {
196,550✔
981
  int32_t rSize = end - start;
196,550✔
982

983
  return rSize >= 0 ? rSize : LOG_BUF_SIZE(pLogBuf) + rSize;
196,550✔
984
}
985

986
static void taosWriteSlowLog(SLogBuff *pLogBuf) {
2,149,458✔
987
  int32_t lock = atomic_val_compare_exchange_32(&pLogBuf->lock, 0, 1);
2,149,458✔
988
  if (lock == 1) return;
2,149,458!
989
  taosWriteLog(pLogBuf);
2,149,458✔
990
  atomic_store_32(&pLogBuf->lock, 0);
2,149,458✔
991
}
992
static void taosWriteLog(SLogBuff *pLogBuf) {
11,649,213✔
993
  int32_t start = LOG_BUF_START(pLogBuf);
11,649,213✔
994
  int32_t end = LOG_BUF_END(pLogBuf);
11,649,213✔
995

996
  if (start == end) {
11,649,213✔
997
    dbgEmptyW++;
11,457,841✔
998
    pLogBuf->writeInterval = LOG_MAX_INTERVAL;
11,457,841✔
999
    return;
11,457,841✔
1000
  }
1001

1002
  int32_t pollSize = taosGetLogRemainSize(pLogBuf, start, end);
191,372✔
1003
  if (pollSize < pLogBuf->minBuffSize) {
191,372!
1004
    pLogBuf->lastDuration += pLogBuf->writeInterval;
191,372✔
1005
    if (pLogBuf->lastDuration < LOG_MAX_WAIT_MSEC) {
191,372✔
1006
      return;
186,194✔
1007
    }
1008
  }
1009

1010
  pLogBuf->lastDuration = 0;
5,178✔
1011

1012
  if (start < end) {
5,178✔
1013
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf) + start, pollSize));
5,176✔
1014
  } else {
1015
    int32_t tsize = LOG_BUF_SIZE(pLogBuf) - start;
2✔
1016
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf) + start, tsize));
2✔
1017

1018
    TAOS_UNUSED(taosWriteFile(pLogBuf->pFile, LOG_BUF_BUFFER(pLogBuf), end));
2✔
1019
  }
1020

1021
  dbgWN++;
5,178✔
1022
  dbgWSize += pollSize;
5,178✔
1023

1024
  if (pollSize < pLogBuf->minBuffSize) {
5,178!
1025
    dbgSmallWN++;
5,178✔
1026
    if (pLogBuf->writeInterval < LOG_MAX_INTERVAL) {
5,178!
1027
      pLogBuf->writeInterval += LOG_INTERVAL_STEP;
×
1028
    }
1029
  } else if (pollSize > LOG_BUF_SIZE(pLogBuf) / 3) {
×
1030
    dbgBigWN++;
×
1031
    pLogBuf->writeInterval = LOG_MIN_INTERVAL;
×
1032
  } else if (pollSize > LOG_BUF_SIZE(pLogBuf) / 4) {
×
1033
    if (pLogBuf->writeInterval > LOG_MIN_INTERVAL) {
×
1034
      pLogBuf->writeInterval -= LOG_INTERVAL_STEP;
×
1035
    }
1036
  }
1037

1038
  LOG_BUF_START(pLogBuf) = (LOG_BUF_START(pLogBuf) + pollSize) % LOG_BUF_SIZE(pLogBuf);
5,178✔
1039

1040
  start = LOG_BUF_START(pLogBuf);
5,178✔
1041
  end = LOG_BUF_END(pLogBuf);
5,178✔
1042

1043
  pollSize = taosGetLogRemainSize(pLogBuf, start, end);
5,178✔
1044
  if (pollSize < pLogBuf->minBuffSize) {
5,178!
1045
    return;
5,178✔
1046
  }
1047

1048
  pLogBuf->writeInterval = 0;
×
1049
}
1050

1051
#define LOG_ROTATE_INTERVAL 3600
1052
#if !defined(TD_ENTERPRISE) || defined(ASSERT_NOT_CORE)
1053
#define LOG_INACTIVE_TIME 7200
1054
#define LOG_ROTATE_BOOT   900
1055
#else
1056
#define LOG_INACTIVE_TIME 5
1057
#define LOG_ROTATE_BOOT   (LOG_INACTIVE_TIME + 1)
1058
#endif
1059

1060
static void *taosLogRotateFunc(void *param) {
4,615✔
1061
  setThreadName("logRotate");
4,615✔
1062
  int32_t code = 0;
4,615✔
1063
  taosWLockLatch(&tsLogRotateLatch);
4,615✔
1064
  // compress or remove the old log files
1065
  TdDirPtr pDir = taosOpenDir(tsLogDir);
4,615✔
1066
  if (!pDir) goto _exit;
4,615!
1067
  TdDirEntryPtr de = NULL;
4,615✔
1068
  while ((de = taosReadDir(pDir))) {
25,458✔
1069
    if (taosDirEntryIsDir(de)) {
20,843✔
1070
      continue;
20,841✔
1071
    }
1072
    char *fname = taosGetDirEntryName(de);
11,611✔
1073
    if (!fname) {
11,611!
1074
      continue;
×
1075
    }
1076

1077
    char *pSec = strrchr(fname, '.');
11,611✔
1078
    if (!pSec) {
11,611!
1079
      continue;
×
1080
    }
1081
    char *pIter = pSec;
11,611✔
1082
    bool  isSec = true;
11,611✔
1083
    while (*(++pIter)) {
26,617✔
1084
      if (!isdigit(*pIter)) {
17,667✔
1085
        isSec = false;
2,661✔
1086
        break;
2,661✔
1087
      }
1088
    }
1089
    if (!isSec) {
11,611✔
1090
      continue;
2,661✔
1091
    }
1092

1093
    int64_t fileSec = 0;
8,950✔
1094
    if ((code = taosStr2int64(pSec + 1, &fileSec)) != 0) {
8,950!
1095
      uWarn("%s:%d failed to convert %s to int64 since %s", __func__, __LINE__, pSec + 1, tstrerror(code));
×
1096
      continue;
×
1097
    }
1098
    if (fileSec <= 100) {
8,950✔
1099
      continue;
8,948✔
1100
    }
1101

1102
    char fullName[PATH_MAX] = {0};
2✔
1103
    snprintf(fullName, sizeof(fullName), "%s%s%s", tsLogDir, TD_DIRSEP, fname);
2✔
1104

1105
    int64_t mtime = 0;
2✔
1106
    if ((code = taosStatFile(fullName, NULL, &mtime, NULL)) != 0) {
2!
1107
      uWarn("%s:%d failed to stat file %s since %s", __func__, __LINE__, fullName, tstrerror(code));
×
1108
      continue;
×
1109
    }
1110

1111
    int64_t inactiveSec = taosGetTimestampMs() / 1000 - mtime;
2✔
1112

1113
    if (inactiveSec < LOG_INACTIVE_TIME) {
2!
1114
      continue;
×
1115
    }
1116

1117
    int32_t days = inactiveSec / 86400 + 1;
2✔
1118
    if (tsLogKeepDays > 0 && days > tsLogKeepDays) {
2!
1119
      TAOS_UNUSED(taosRemoveFile(fullName));
×
1120
      uInfo("file:%s is removed, days:%d, keepDays:%d, sed:%" PRId64, fullName, days, tsLogKeepDays, fileSec);
×
1121
    } else {
1122
      taosKeepOldLog(fullName);  // compress
2✔
1123
    }
1124
  }
1125
  if ((code = taosCloseDir(&pDir)) != 0) {
4,615!
1126
    uWarn("%s:%d failed to close dir %s since %s\n", __func__, __LINE__, tsLogDir, tstrerror(code));
×
1127
  }
1128

1129
  if (tsLogKeepDays > 0) {
4,615✔
1130
    taosRemoveOldFiles(tsLogDir, tsLogKeepDays);
3✔
1131
  }
1132
_exit:
4,612✔
1133
  taosWUnLockLatch(&tsLogRotateLatch);
4,615✔
1134
  return NULL;
4,615✔
1135
}
1136

1137
static void *taosAsyncOutputLog(void *param) {
5,879✔
1138
  SLogBuff *pLogBuf = (SLogBuff *)tsLogObj.logHandle;
5,879✔
1139
  SLogBuff *pSlowBuf = (SLogBuff *)tsLogObj.slowHandle;
5,879✔
1140

1141
  setThreadName("log");
5,879✔
1142
  int32_t count = 0;
5,879✔
1143
  int32_t updateCron = 0;
5,879✔
1144
  int32_t writeInterval = 0;
5,879✔
1145
  int64_t lastCheckSec = taosGetTimestampMs() / 1000 - (LOG_ROTATE_INTERVAL - LOG_ROTATE_BOOT);
5,879✔
1146

1147
  while (1) {
9,488,013✔
1148
    if (pSlowBuf) {
9,493,892✔
1149
      writeInterval = TMIN(pLogBuf->writeInterval, pSlowBuf->writeInterval);
2,147,484✔
1150
    } else {
1151
      writeInterval = pLogBuf->writeInterval;
7,346,408✔
1152
    }
1153
    count += writeInterval;
9,493,892✔
1154
    updateCron++;
9,493,892✔
1155
    taosMsleep(writeInterval);
9,493,892✔
1156
    if (count > 1000) {
9,493,884✔
1157
      TAOS_UNUSED(osUpdate());
228,880✔
1158
      count = 0;
228,880✔
1159
    }
1160

1161
    // Polling the buffer
1162
    taosWriteLog(pLogBuf);
9,493,884✔
1163
    if (pSlowBuf) taosWriteSlowLog(pSlowBuf);
9,493,884✔
1164

1165
    if (pLogBuf->stop || (pSlowBuf && pSlowBuf->stop)) {
9,493,884!
1166
      pLogBuf->lastDuration = LOG_MAX_WAIT_MSEC;
5,871✔
1167
      taosWriteLog(pLogBuf);
5,871✔
1168
      if (pSlowBuf) taosWriteSlowLog(pSlowBuf);
5,871✔
1169
      break;
5,871✔
1170
    }
1171

1172
    // process the log rotation every LOG_ROTATE_INTERVAL
1173
    int64_t curSec = taosGetTimestampMs() / 1000;
9,488,013✔
1174
    if (curSec >= lastCheckSec) {
9,488,013!
1175
      if ((curSec - lastCheckSec) >= LOG_ROTATE_INTERVAL) {
9,488,013✔
1176
        TdThread     thread;
1177
        TdThreadAttr attr;
1178
        (void)taosThreadAttrInit(&attr);
4,615✔
1179
        (void)taosThreadAttrSetDetachState(&attr, PTHREAD_CREATE_DETACHED);
4,615✔
1180
        if (taosThreadCreate(&thread, &attr, taosLogRotateFunc, tsLogObj.logHandle) == 0) {
4,615!
1181
          uInfo("process log rotation");
4,615!
1182
          lastCheckSec = curSec;
4,615✔
1183
        } else {
1184
          uWarn("failed to create thread to process log rotation");
×
1185
        }
1186
        (void)taosThreadAttrDestroy(&attr);
4,615✔
1187
      }
1188
    } else if (curSec < lastCheckSec) {
×
1189
      lastCheckSec = curSec;
×
1190
    }
1191
  }
1192

1193
  return NULL;
5,871✔
1194
}
1195

1196
bool taosAssertDebug(bool condition, const char *file, int32_t line, bool core, const char *format, ...) {
×
1197
  if (condition) return false;
×
1198

1199
  const char *flags = "UTL FATAL ";
×
1200
  ELogLevel   level = DEBUG_FATAL;
×
1201
  int32_t     dflag = 255;  // tsLogEmbedded ? 255 : uDebugFlag
×
1202
  char        buffer[LOG_MAX_LINE_BUFFER_SIZE];
1203
  int32_t     len = taosBuildLogHead(buffer, flags);
×
1204

1205
  va_list argpointer;
1206
  va_start(argpointer, format);
×
1207
  len = len + vsnprintf(buffer + len, LOG_MAX_LINE_BUFFER_SIZE - len, format, argpointer);
×
1208
  va_end(argpointer);
×
1209
  buffer[len++] = '\n';
×
1210
  buffer[len] = 0;
×
1211
  taosPrintLogImp(1, 255, buffer, len);
×
1212

1213
  taosPrintLog(flags, level, dflag, "tAssert at file %s:%d exit:%d", file, line, tsAssert);
×
1214
  taosPrintTrace(flags, level, dflag, -1);
×
1215

1216
  if (tsAssert || core) {
×
1217
    taosCloseLog();
×
1218
    taosMsleep(300);
×
1219

1220
#ifdef NDEBUG
1221
    abort();
1222
#else
1223
    assert(0);
×
1224
#endif
1225
  }
1226

1227
  return true;
×
1228
}
1229

1230
void taosLogCrashInfo(char *nodeType, char *pMsg, int64_t msgLen, int signum, void *sigInfo) {
×
1231
  const char *flags = "UTL FATAL ";
×
1232
  ELogLevel   level = DEBUG_FATAL;
×
1233
  int32_t     dflag = 255;
×
1234
  char        filepath[PATH_MAX] = {0};
×
1235
  TdFilePtr   pFile = NULL;
×
1236

1237
  if (pMsg && msgLen > 0) {
×
1238
    snprintf(filepath, sizeof(filepath), "%s%s.%sCrashLog", tsLogDir, TD_DIRSEP, nodeType);
×
1239

1240
    pFile = taosOpenFile(filepath, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_APPEND);
×
1241
    if (pFile == NULL) {
×
1242
      taosPrintLog(flags, level, dflag, "failed to open file:%s since %s", filepath, terrstr());
×
1243
      goto _return;
×
1244
    }
1245

1246
    if (taosLockFile(pFile) < 0) {
×
1247
      taosPrintLog(flags, level, dflag, "failed to lock file:%s since %s", filepath, terrstr());
×
1248
      goto _return;
×
1249
    }
1250

1251
    int64_t writeSize = taosWriteFile(pFile, &msgLen, sizeof(msgLen));
×
1252
    if (sizeof(msgLen) != writeSize) {
×
1253
      TAOS_UNUSED(taosUnLockFile(pFile));
×
1254
      taosPrintLog(flags, level, dflag, "failed to write len to file:%s,%p wlen:%" PRId64 " tlen:%lu since %s",
×
1255
                   filepath, pFile, writeSize, sizeof(msgLen), terrstr());
1256
      goto _return;
×
1257
    }
1258

1259
    writeSize = taosWriteFile(pFile, pMsg, msgLen);
×
1260
    if (msgLen != writeSize) {
×
1261
      TAOS_UNUSED(taosUnLockFile(pFile));
×
1262
      taosPrintLog(flags, level, dflag, "failed to write file:%s,%p wlen:%" PRId64 " tlen:%" PRId64 " since %s",
×
1263
                   filepath, pFile, writeSize, msgLen, terrstr());
1264
      goto _return;
×
1265
    }
1266

1267
    TAOS_UNUSED(taosUnLockFile(pFile));
×
1268
  }
1269

1270
_return:
×
1271

1272
  if (pFile) (void)taosCloseFile(&pFile);
×
1273

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

1276
#ifdef _TD_DARWIN_64
1277
  taosPrintTrace(flags, level, dflag, 4);
1278
#elif !defined(WINDOWS)
1279
  taosPrintLog(flags, level, dflag, "sender PID:%d cmdline:%s", ((siginfo_t *)sigInfo)->si_pid,
×
1280
               taosGetCmdlineByPID(((siginfo_t *)sigInfo)->si_pid));
1281
  taosPrintTrace(flags, level, dflag, 3);
×
1282
#else
1283
  taosPrintTrace(flags, level, dflag, 8);
1284
#endif
1285

1286
  taosMemoryFree(pMsg);
×
1287
}
×
1288

1289
void taosReadCrashInfo(char *filepath, char **pMsg, int64_t *pMsgLen, TdFilePtr *pFd) {
×
1290
  const char *flags = "UTL FATAL ";
×
1291
  ELogLevel   level = DEBUG_FATAL;
×
1292
  int32_t     dflag = 255;
×
1293
  TdFilePtr   pFile = NULL;
×
1294
  bool        truncateFile = false;
×
1295
  char       *buf = NULL;
×
1296

1297
  if (NULL == *pFd) {
×
1298
    int64_t filesize = 0;
×
1299
    if (taosStatFile(filepath, &filesize, NULL, NULL) < 0) {
×
1300
      if (TAOS_SYSTEM_ERROR(ENOENT) == terrno) {
×
1301
        return;
×
1302
      }
1303

1304
      taosPrintLog(flags, level, dflag, "failed to stat file:%s since %s", filepath, terrstr());
×
1305
      return;
×
1306
    }
1307

1308
    if (filesize <= 0) {
×
1309
      return;
×
1310
    }
1311

1312
    pFile = taosOpenFile(filepath, TD_FILE_READ | TD_FILE_WRITE);
×
1313
    if (pFile == NULL) {
×
1314
      if (ENOENT == errno) {
×
1315
        return;
×
1316
      }
1317

1318
      taosPrintLog(flags, level, dflag, "failed to open file:%s since %s", filepath, terrstr());
×
1319
      return;
×
1320
    }
1321

1322
    TAOS_UNUSED(taosLockFile(pFile));
×
1323
  } else {
1324
    pFile = *pFd;
×
1325
  }
1326

1327
  int64_t msgLen = 0;
×
1328
  int64_t readSize = taosReadFile(pFile, &msgLen, sizeof(msgLen));
×
1329
  if (sizeof(msgLen) != readSize) {
×
1330
    truncateFile = true;
×
1331
    if (readSize < 0) {
×
1332
      taosPrintLog(flags, level, dflag, "failed to read len from file:%s,%p wlen:%" PRId64 " tlen:%lu since %s",
×
1333
                   filepath, pFile, readSize, sizeof(msgLen), terrstr());
1334
    }
1335
    goto _return;
×
1336
  }
1337

1338
  buf = taosMemoryMalloc(msgLen);
×
1339
  if (NULL == buf) {
×
1340
    taosPrintLog(flags, level, dflag, "failed to malloc buf, size:%" PRId64, msgLen);
×
1341
    goto _return;
×
1342
  }
1343

1344
  readSize = taosReadFile(pFile, buf, msgLen);
×
1345
  if (msgLen != readSize) {
×
1346
    truncateFile = true;
×
1347
    taosPrintLog(flags, level, dflag, "failed to read file:%s,%p wlen:%" PRId64 " tlen:%" PRId64 " since %s", filepath,
×
1348
                 pFile, readSize, msgLen, terrstr());
1349
    goto _return;
×
1350
  }
1351

1352
  *pMsg = buf;
×
1353
  *pMsgLen = msgLen;
×
1354
  *pFd = pFile;
×
1355

1356
  return;
×
1357

1358
_return:
×
1359

1360
  if (truncateFile) {
×
1361
    TAOS_UNUSED(taosFtruncateFile(pFile, 0));
×
1362
  }
1363
  TAOS_UNUSED(taosUnLockFile(pFile));
×
1364
  TAOS_UNUSED(taosCloseFile(&pFile));
×
1365
  taosMemoryFree(buf);
×
1366

1367
  *pMsg = NULL;
×
1368
  *pMsgLen = 0;
×
1369
  *pFd = NULL;
×
1370
}
1371

1372
void taosReleaseCrashLogFile(TdFilePtr pFile, bool truncateFile) {
×
1373
  if (truncateFile) {
×
1374
    TAOS_UNUSED(taosFtruncateFile(pFile, 0));
×
1375
  }
1376

1377
  TAOS_UNUSED(taosUnLockFile(pFile));
×
1378
  TAOS_UNUSED(taosCloseFile(&pFile));
×
1379
}
×
1380

1381
#ifdef NDEBUG
1382
bool taosAssertRelease(bool condition) {
1383
  if (condition) return false;
1384

1385
  const char *flags = "UTL FATAL ";
1386
  ELogLevel   level = DEBUG_FATAL;
1387
  int32_t     dflag = 255;  // tsLogEmbedded ? 255 : uDebugFlag
1388

1389
  taosPrintLog(flags, level, dflag, "tAssert called in release mode, exit:%d", tsAssert);
1390
  taosPrintTrace(flags, level, dflag, 0);
1391

1392
  if (tsAssert) {
1393
    taosMsleep(300);
1394
    abort();
1395
  }
1396

1397
  return true;
1398
}
1399
#endif
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