同时具备多线程和多进程安全的写日志工具

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 接口请浏览:https://github.com/eyjian/mooon/blob/master/mooon/include/mooon/sys/log.h 实现头文件请浏览:https://github.
接口请浏览: https://github.com/eyjian/mooon/blob/master/mooon/include/mooon/sys/log.h
实现头文件请浏览: https://github.com/eyjian/mooon/blob/master/mooon/include/mooon/sys/safe_logger.h

测试代码: https://github.com/eyjian/mooon/blob/master/mooon/test/sys/test_safe_logger.cpp

使用示例:
MYLOG_DEBUG("[%d]MMMMM", 2015);

支持自动添加换行符,默认会自动添加换行符,但可以禁止自动添加换行符。还支持自动在行尾添加点号等功能。

下面是 实现

  1. #include "mooon/sys/safe_logger.h"
  2. #include "mooon/sys/datetime_utils.h"
  3. #include "mooon/sys/file_locker.h"
  4. #include "mooon/sys/file_utils.h"
  5. #include "mooon/utils/scoped_ptr.h"
  6. #include "mooon/utils/string_utils.h"
  7. #include libgen.h>
  8. #include pthread.h>
  9. #include sstream>
  10. #include syslog.h>
  11. #include unistd.h>

  12. #define WRITE_SYSLOG 0 // 出错时是否记录系统日志,1表示记录
  13. SYS_NAMESPACE_BEGIN

  14. // 线程级别的
  15. static __thread int sg_thread_log_fd = -1;

  16. CSafeLogger* create_safe_logger(bool enable_program_path, uint16_t log_line_size) throw (CSyscallException)
  17. {
  18.     std::string log_dirpath = get_log_dirpath(enable_program_path);
  19.     std::string log_filename = get_log_filename();
  20.     CSafeLogger* logger = new CSafeLogger(log_dirpath.c_str(), log_filename.c_str(), log_line_size);

  21.     set_log_level_by_env(logger);
  22.     enable_screen_log_by_env(logger);
  23.     enable_trace_log_by_env(logger);
  24.     set_log_filesize_by_env(logger);
  25.     set_log_backup_by_env(logger);

  26.     return logger;
  27. }

  28. CSafeLogger* create_safe_logger(const std::string& log_dirpath, const std::string& cpp_filename, uint16_t log_line_size) throw (CSyscallException)
  29. {
  30.     char* cpp_filepath = strdup(cpp_filename.c_str());
  31.     std::string only_filename = basename(cpp_filepath);
  32.     free(cpp_filepath);

  33.     std::string log_filename = utils::CStringUtils::replace_suffix(only_filename, ".log");
  34.     CSafeLogger* logger = new CSafeLogger(log_dirpath.c_str(), log_filename.c_str(), log_line_size);

  35.     set_log_level_by_env(logger);
  36.     enable_screen_log_by_env(logger);
  37.     enable_trace_log_by_env(logger);
  38.     set_log_filesize_by_env(logger);
  39.     set_log_backup_by_env(logger);

  40.     return logger;
  41. }

  42. ////////////////////////////////////////////////////////////////////////////////
  43. CSafeLogger::CSafeLogger(const char* log_dir, const char* log_filename, uint16_t log_line_size) throw (CSyscallException)
  44.     :_auto_adddot(false)
  45.     ,_auto_newline(true)
  46.     ,_bin_log_enabled(false)
  47.     ,_trace_log_enabled(false)
  48.     ,_raw_log_enabled(false)
  49.     ,_screen_enabled(false)
  50.     ,_log_dir(log_dir)
  51.     ,_log_filename(log_filename)
  52.     ,_log_filepath(_log_dir + std::string("/") + _log_filename)
  53. {
  54.     atomic_set(&_max_bytes, DEFAULT_LOG_FILE_SIZE);
  55.     atomic_set(&_log_level, LOG_LEVEL_INFO);
  56.     atomic_set(&_backup_number, DEFAULT_LOG_FILE_BACKUP_NUMBER);

  57.     // 保证日志行最大长度不小于指定值
  58.     _log_line_size = (log_line_size LOG_LINE_SIZE_MIN)? LOG_LINE_SIZE_MIN: log_line_size;
  59.     if (_log_line_size > LOG_LINE_SIZE_MAX)
  60.         _log_line_size = LOG_LINE_SIZE_MAX;

  61.     int log_fd = open(_log_filepath.c_str(), O_WRONLY|O_CREAT|O_APPEND, FILE_DEFAULT_PERM);
  62.     if (-1 == log_fd)
  63.     {
  64.         int errcode = errno;
  65.         fprintf(stderr, "[%d:%lu] SafeLogger open %s error: %m\n", getpid(), pthread_self(), _log_filepath.c_str());

  66.         THROW_SYSCALL_EXCEPTION(NULL, errcode, "open");
  67.     }
  68.     else
  69.     {
  70.         close(log_fd);
  71.     }
  72. }

  73. CSafeLogger::~CSafeLogger()
  74. {
  75.     (void)release();
  76. }

  77. int CSafeLogger::release()
  78. {
  79.     int ret = 0;
  80.     if (sg_thread_log_fd != -1)
  81.     {
  82. #if 0 // 由系统决定何时fsync
  83.         ret = fsync(sg_thread_log_fd);
  84.         if (-1 == ret)
  85.         {
  86.             fprintf(stderr, "process(%u,%lu) fsync fd(%d) error: %m\n", getpid(), pthread_self(), sg_thread_log_fd);
  87.         }
  88.         else
  89. #endif
  90.         {
  91.             ret = close(sg_thread_log_fd);
  92.             if (0 == ret)
  93.                 sg_thread_log_fd = -1;
  94.             else
  95.                 fprintf(stderr, "process(%u,%lu) close fd(%d) error: %m\n", getpid(), pthread_self(), sg_thread_log_fd);
  96.         }
  97.     }

  98.     return ret;
  99. }

  100. void CSafeLogger::enable_screen(bool enabled)
  101. {
  102.     _screen_enabled = enabled;
  103. }

  104. void CSafeLogger::enable_bin_log(bool enabled)
  105. {
  106.     _bin_log_enabled = enabled;
  107. }

  108. void CSafeLogger::enable_trace_log(bool enabled)
  109. {
  110.     _trace_log_enabled = enabled;
  111. }

  112. void CSafeLogger::enable_raw_log(bool enabled)
  113. {
  114.     _raw_log_enabled = enabled;
  115. }

  116. void CSafeLogger::enable_auto_adddot(bool enabled)
  117. {
  118.     _auto_adddot = enabled;
  119. }

  120. void CSafeLogger::enable_auto_newline(bool enabled)
  121. {
  122.     _auto_newline = enabled;
  123. }

  124. void CSafeLogger::set_log_level(log_level_t log_level)
  125. {
  126.     atomic_set(&_log_level, log_level);
  127. }

  128. void CSafeLogger::set_single_filesize(uint32_t filesize)
  129. {
  130.     uint32_t max_bytes = (filesize LOG_LINE_SIZE_MIN*10)? LOG_LINE_SIZE_MIN*10: filesize;
  131.     atomic_set(&_max_bytes, max_bytes);
  132. }

  133. void CSafeLogger::set_backup_number(uint16_t backup_number)
  134. {
  135.     atomic_set(&_backup_number, backup_number);
  136. }

  137. bool CSafeLogger::enabled_bin()
  138. {
  139.     return _bin_log_enabled;
  140. }

  141. bool CSafeLogger::enabled_detail()
  142. {
  143.     return atomic_read(&_log_level) = LOG_LEVEL_DETAIL;
  144. }

  145. bool CSafeLogger::enabled_debug()
  146. {
  147.     return atomic_read(&_log_level) = LOG_LEVEL_DEBUG;
  148. }

  149. bool CSafeLogger::enabled_info()
  150. {
  151.     return atomic_read(&_log_level) = LOG_LEVEL_INFO;
  152. }

  153. bool CSafeLogger::enabled_warn()
  154. {
  155.     return atomic_read(&_log_level) = LOG_LEVEL_WARN;
  156. }

  157. bool CSafeLogger::enabled_error()
  158. {
  159.     return atomic_read(&_log_level) = LOG_LEVEL_ERROR;
  160. }

  161. bool CSafeLogger::enabled_fatal()
  162. {
  163.     return atomic_read(&_log_level) = LOG_LEVEL_FATAL;
  164. }

  165. bool CSafeLogger::enabled_state()
  166. {
  167.     return atomic_read(&_log_level) = LOG_LEVEL_STATE;
  168. }

  169. bool CSafeLogger::enabled_trace()
  170. {
  171.     return _trace_log_enabled;
  172. }

  173. bool CSafeLogger::enabled_raw()
  174. {
  175.     return _raw_log_enabled;
  176. }

  177. void CSafeLogger::log_detail(const char* filename, int lineno, const char* module_name, const char* format, va_list& args)
  178. {
  179.     if (enabled_detail())
  180.         do_log(LOG_LEVEL_DETAIL, filename, lineno, module_name, format, args);
  181. }

  182. void CSafeLogger::log_detail(const char* filename, int lineno, const char* module_name, const char* format, ...)
  183. {
  184.     if (enabled_detail())
  185.     {
  186.         va_list args;
  187.         va_start(args, format);
  188.         utils::VaListHelper vh(args);

  189.         do_log(LOG_LEVEL_DETAIL, filename, lineno, module_name, format, args);
  190.     }
  191. }

  192. void CSafeLogger::log_debug(const char* filename, int lineno, const char* module_name, const char* format, va_list& args)
  193. {
  194.     if (enabled_detail())
  195.         do_log(LOG_LEVEL_DEBUG, filename, lineno, module_name, format, args);
  196. }

  197. void CSafeLogger::log_debug(const char* filename, int lineno, const char* module_name, const char* format, ...)
  198. {
  199.     if (enabled_debug())
  200.     {
  201.         va_list args;
  202.         va_start(args, format);
  203.         utils::VaListHelper vh(args);

  204.         do_log(LOG_LEVEL_DEBUG, filename, lineno, module_name, format, args);
  205.     }
  206. }

  207. void CSafeLogger::log_info(const char* filename, int lineno, const char* module_name, const char* format, va_list& args)
  208. {
  209.     if (enabled_info())
  210.         do_log(LOG_LEVEL_INFO, filename, lineno, module_name, format, args);
  211. }

  212. void CSafeLogger::log_info(const char* filename, int lineno, const char* module_name, const char* format, ...)
  213. {
  214.     if (enabled_info())
  215.     {
  216.         va_list args;
  217.         va_start(args, format);
  218.         utils::VaListHelper vh(args);

  219.         do_log(LOG_LEVEL_INFO, filename, lineno, module_name, format, args);
  220.     }
  221. }

  222. void CSafeLogger::log_warn(const char* filename, int lineno, const char* module_name, const char* format, va_list& args)
  223. {
  224.     if (enabled_warn())
  225.         do_log(LOG_LEVEL_WARN, filename, lineno, module_name, format, args);
  226. }

  227. void CSafeLogger::log_warn(const char* filename, int lineno, const char* module_name, const char* format, ...)
  228. {
  229.     if (enabled_warn())
  230.     {
  231.         va_list args;
  232.         va_start(args, format);
  233.         utils::VaListHelper vh(args);

  234.         do_log(LOG_LEVEL_WARN, filename, lineno, module_name, format, args);
  235.     }
  236. }

  237. void CSafeLogger::log_error(const char* filename, int lineno, const char* module_name, const char* format, va_list& args)
  238. {
  239.     if (enabled_error())
  240.         do_log(LOG_LEVEL_ERROR, filename, lineno, module_name, format, args);
  241. }

  242. void CSafeLogger::log_error(const char* filename, int lineno, const char* module_name, const char* format, ...)
  243. {
  244.     if (enabled_error())
  245.     {
  246.         va_list args;
  247.         va_start(args, format);
  248.         utils::VaListHelper vh(args);

  249.         do_log(LOG_LEVEL_ERROR, filename, lineno, module_name, format, args);
  250.     }
  251. }

  252. void CSafeLogger::log_fatal(const char* filename, int lineno, const char* module_name, const char* format, va_list& args)
  253. {
  254.     if (enabled_fatal())
  255.         do_log(LOG_LEVEL_FATAL, filename, lineno, module_name, format, args);
  256. }

  257. void CSafeLogger::log_fatal(const char* filename, int lineno, const char* module_name, const char* format, ...)
  258. {
  259.     if (enabled_fatal())
  260.     {
  261.         va_list args;
  262.         va_start(args, format);
  263.         utils::VaListHelper vh(args);

  264.         do_log(LOG_LEVEL_FATAL, filename, lineno, module_name, format, args);
  265.     }
  266. }

  267. void CSafeLogger::log_state(const char* filename, int lineno, const char* module_name, const char* format, va_list& args)
  268. {
  269.     if (enabled_state())
  270.         do_log(LOG_LEVEL_STATE, filename, lineno, module_name, format, args);
  271. }

  272. void CSafeLogger::log_state(const char* filename, int lineno, const char* module_name, const char* format, ...)
  273. {
  274.     if (enabled_state())
  275.     {
  276.         va_list args;
  277.         va_start(args, format);
  278.         utils::VaListHelper vh(args);

  279.         do_log(LOG_LEVEL_STATE, filename, lineno, module_name, format, args);
  280.     }
  281. }

  282. void CSafeLogger::log_trace(const char* filename, int lineno, const char* module_name, const char* format, va_list& args)
  283. {
  284.     if (enabled_trace())
  285.         do_log(LOG_LEVEL_TRACE, filename, lineno, module_name, format, args);
  286. }

  287. void CSafeLogger::log_trace(const char* filename, int lineno, const char* module_name, const char* format, ...)
  288. {
  289.     if (enabled_trace())
  290.     {
  291.         va_list args;
  292.         va_start(args, format);
  293.         utils::VaListHelper vh(args);

  294.         do_log(LOG_LEVEL_TRACE, filename, lineno, module_name, format, args);
  295.     }
  296. }

  297. void CSafeLogger::log_raw(const char* format, va_list& args)
  298. {
  299.     if (enabled_raw())
  300.         do_log(LOG_LEVEL_RAW, NULL, -1, NULL, format, args);
  301. }

  302. void CSafeLogger::log_raw(const char* format, ...)
  303. {
  304.     if (enabled_raw())
  305.     {
  306.         va_list args;
  307.         va_start(args, format);
  308.         utils::VaListHelper vh(args);
  309.         do_log(LOG_LEVEL_RAW, NULL, -1, NULL, format, args);
  310.     }
  311. }

  312. void CSafeLogger::log_bin(const char* filename, int lineno, const char* module_name, const char* log, uint16_t size)
  313. {
  314.     if (enabled_bin())
  315.     {
  316.         std::string str(size*2, '\0');
  317.         char* str_p = const_castchar*>(str.data());
  318.         for (uint16_t i=0; isize; ++i)
  319.         {
  320.             snprintf(str_p, 3, "%02X", (int)log[i]);
  321.             str_p += 2;
  322.         }

  323.         va_list args;
  324.         do_log(LOG_LEVEL_BIN, filename, lineno, module_name, str.c_str(), args);
  325.     }
  326. }

  327. int CSafeLogger::get_thread_log_fd() const
  328. {
  329.     if (-1 == sg_thread_log_fd)
  330.     {
  331.         sg_thread_log_fd = open(_log_filepath.c_str(), O_WRONLY|O_CREAT|O_APPEND, FILE_DEFAULT_PERM);
  332.         if (-1 == sg_thread_log_fd)
  333.             fprintf(stderr, "open %s error: %m\n", _log_filepath.c_str());
  334.     }

  335.     return sg_thread_log_fd;
  336. }

  337. bool CSafeLogger::need_rotate(int fd) const
  338. {
  339.     off_t file_size = CFileUtils::get_file_size(fd);
  340.     return file_size > static_castoff_t>(atomic_read(&_max_bytes));
  341. }

  342. void CSafeLogger::do_log(log_level_t log_level, const char* filename, int lineno, const char* module_name, const char* format, va_list& args)
  343. {
  344.     int log_real_size;
  345.     utils::ScopedArraychar> log_line(new char[_log_line_size]);

  346.     if (LOG_LEVEL_RAW == log_level)
  347.     {
  348.         // fix_vsnprintf()的返回值包含了结尾符在内的长度
  349.         log_real_size = utils::CStringUtils::fix_vsnprintf(log_line.get(), _log_line_size, format, args);
  350.         --log_real_size; // 结尾符不需要写入日志文件中
  351.     }
  352.     else
  353.     {
  354.         std::stringstream log_header; // 每条日志的头
  355.         char datetime[sizeof("2012-12-12 12:12:12/0123456789")];
  356.         get_formatted_current_datetime(datetime, sizeof(datetime));

  357.         // 日志头内容:[日期][线程ID/进程ID][日志级别][模块名][代码文件名][代码行号]
  358.         log_header "[" datetime "]"
  359.                     "[" pthread_self() "/" getpid() "]"
  360.                     "[" get_log_level_name(log_level) "]";
  361.         if (module_name != NULL)
  362.             log_header "[" module_name "]";
  363.         if (filename != NULL)
  364.             log_header "[" utils::CStringUtils::extract_filename(filename) ":" lineno "]";

  365.         int m, n;
  366.         // 注意fix_snprintf()的返回值大小包含了结尾符
  367.         m = utils::CStringUtils::fix_snprintf(log_line.get(), _log_line_size, "%s", log_header.str().c_str());

  368.         if (LOG_LEVEL_BIN == log_level)
  369.             n = utils::CStringUtils::fix_snprintf(log_line.get()+m-1, _log_line_size-m, "%s", format);
  370.         else
  371.             n = utils::CStringUtils::fix_vsnprintf(log_line.get()+m-1, _log_line_size-m, format, args);
  372.         log_real_size = m + n - 2;

  373.         // 是否自动添加结尾用的点号
  374.         if (_auto_adddot)
  375.         {
  376.             // 如果已有结尾的点,则不再添加,以免重复
  377.             if (log_line.get()[log_real_size-1] != '.')
  378.             {
  379.                 log_line.get()[log_real_size] = '.';
  380.                 ++log_real_size;
  381.             }
  382.         }

  383.         // 是否自动换行
  384.         if (_auto_newline)
  385.         {
  386.             // 如果已有一个换行符,则不再添加
  387.             if (log_line.get()[log_real_size-1] != '\n')
  388.             {
  389.                 log_line.get()[log_real_size] = '\n';
  390.                 ++log_real_size;
  391.             }
  392.         }
  393.     }

  394.     // 允许打屏
  395.     if (_screen_enabled)
  396.     {
  397.         (void)write(STDOUT_FILENO, log_line.get(), log_real_size);
  398.     }

  399.     if (false)
  400.     {
  401.         // 异步写入日志文件
  402.         //log_line.release();
  403.     }
  404.     else
  405.     {
  406.         // 同步写入日志文件
  407.         int thread_log_fd = get_thread_log_fd();
  408.         if (thread_log_fd != -1)
  409.         {
  410.             write_log(thread_log_fd, log_line.get(), log_real_size);
  411.         }
  412.         else
  413.         {
  414.             fprintf(stderr, "process(%u,%lu) without thread log\n", getpid(), pthread_self());

  415. #if WRITE_SYSLOG==1
  416.             openlog("mooon-safe-logger", LOG_CONS|LOG_PID, 0);
  417.             syslog(LOG_ERR, "process(%u,%lu) without thread log\n", getpid(), pthread_self());
  418.             closelog();
  419. #endif // WRITE_SYSLOG
  420.         }
  421.     }
  422. }

  423. void CSafeLogger::rotate_log()
  424. {
  425.     std::string new_path; // 滚动后的文件路径,包含目录和文件名
  426.     std::string old_path; // 滚动前的文件路径,包含目录和文件名

  427.     // 历史滚动
  428.     int backup_number = atomic_read(&_backup_number);
  429.     for (int i=backup_number-1; i>1; --i)
  430.     {
  431.         new_path = _log_dir + std::string("/") + _log_filename + std::string(".") + utils::CStringUtils::any2string(static_castint>(i));
  432.         old_path = _log_dir + std::string("/") + _log_filename + std::string(".") + utils::CStringUtils::any2string(static_castint>(i-1));

  433.         if (0 == access(old_path.c_str(), F_OK))
  434.         {
  435.             if (-1 == rename(old_path.c_str(), new_path.c_str()))
  436.                 fprintf(stderr, "[%d:%lu] SafeLogger rename %s to %s error: %m.\n", getpid(), pthread_self(), old_path.c_str(), new_path.c_str());
  437.         }
  438.         else
  439.         {
  440.             if (errno != ENOENT)
  441.                 fprintf(stderr, "[%d:%lu] SafeLogger access %s error: %m.\n", getpid(), pthread_self(), old_path.c_str());
  442.         }
  443.     }

  444.     if (backup_number > 0)
  445.     {
  446.         // 当前滚动
  447.         new_path = _log_dir + std::string("/") + _log_filename + std::string(".1");
  448.         if (0 == access(_log_filepath.c_str(), F_OK))
  449.         {
  450.             if (-1 == rename(_log_filepath.c_str(), new_path.c_str()))
  451.                 fprintf(stderr, "[%d:%lu] SafeLogger rename %s to %s error: %m\n", getpid(), pthread_self(), _log_filepath.c_str(), new_path.c_str());
  452.         }
  453.         else
  454.         {
  455.             if (errno != ENOENT)
  456.                 fprintf(stderr, "[%d:%lu] SafeLogger access %s error: %m\n", getpid(), pthread_self(), _log_filepath.c_str());
  457.         }
  458.     }

  459.     // 重新创建
  460.     //fprintf(stdout, "[%d:%lu] SafeLogger create %s\n", getpid(), pthread_self(), _log_filepath.c_str());
  461.     int new_log_fd = open(_log_filepath.c_str(), O_WRONLY|O_CREAT|O_APPEND, FILE_DEFAULT_PERM); // O_EXCL
  462.     if (new_log_fd != -1)
  463.     {
  464.         sg_thread_log_fd = new_log_fd;
  465.     }
  466.     else
  467.     {
  468.         fprintf(stderr, "[%d:%lu] SafeLogger create %s error: %m\n", getpid(), pthread_self(), _log_filepath.c_str());

  469. #if WRITE_SYSLOG==1
  470.         openlog("mooon-safe-logger", LOG_CONS|LOG_PID, 0);
  471.         syslog(LOG_ERR, "[%d:%lu] SafeLogger create %s error: %m\n", getpid(), pthread_self(), _log_filepath.c_str());
  472.         closelog();
  473. #endif // WRITE_SYSLOG
  474.     }
  475. }

  476. void CSafeLogger::write_log(int thread_log_fd, const char* log_line, int log_line_size)
  477. {
  478.     int bytes = write(thread_log_fd, log_line, log_line_size);
  479.     if (-1 == bytes)
  480.     {
  481.         fprintf(stderr, "[%d:%lu] SafeLogger[%d] write error: %m\n", getpid(), pthread_self(), thread_log_fd);
  482.     }
  483.     else if (0 == bytes)
  484.     {
  485.         fprintf(stderr, "[%d:%lu] write nothing: SafeLogger[%d]\n", getpid(), pthread_self(), thread_log_fd);
  486.     }
  487.     else if (bytes > 0)
  488.     {
  489.         try
  490.         {
  491.             // 判断是否需要滚动
  492.             if (need_rotate(thread_log_fd))
  493.             {
  494.                 std::string lock_path = _log_dir + std::string("/.") + _log_filename + std::string(".lock");
  495.                 FileLocker file_locker(lock_path.c_str(), true); // 确保这里一定加锁

  496.                 // _fd可能已被其它进程或线程滚动了,所以这里需要重新open一下
  497.                 int new_log_fd = open(_log_filepath.c_str(), O_WRONLY|O_CREAT|O_APPEND, FILE_DEFAULT_PERM);
  498.                 if (-1 == new_log_fd)
  499.                 {
  500.                     fprintf(stderr, "[%d:%lu] SafeLogger open %s error: %m\n", getpid(), pthread_self(), _log_filepath.c_str());
  501.                 }
  502.                 else
  503.                 {
  504.                     try
  505.                     {
  506.                         release();

  507.                         if (!need_rotate(new_log_fd))
  508.                         {
  509.                             // 其它进程或线程抢先做了滚动
  510.                             sg_thread_log_fd = new_log_fd;
  511.                         }
  512.                         else
  513.                         {
  514.                             close(new_log_fd);
  515.                             rotate_log();
  516.                         }
  517.                     }
  518.                     catch (CSyscallException& syscall_ex)
  519.                     {
  520.                         fprintf(stderr, "[%d:%lu] SafeLogger[%d] rotate error: %s.\n", getpid(), pthread_self(), new_log_fd, syscall_ex.str().c_str());
  521.                     }
  522.                 }
  523.             }
  524.         }
  525.         catch (CSyscallException& syscall_ex)
  526.         {
  527.             fprintf(stderr, "[%d:%lu] SafeLogger[%d] rotate error: %s\n", getpid(), pthread_self(), thread_log_fd, syscall_ex.str().c_str());
  528.         }
  529.     }
  530. }

  531. SYS_NAMESPACE_END





相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
7天前
|
UED 开发者 Python
探索操作系统的心脏:理解进程与线程
【8月更文挑战第31天】在数字世界的海洋中,操作系统犹如一艘巨轮,其稳定航行依赖于精密的进程与线程机制。本文将揭开这一机制的神秘面纱,通过深入浅出的语言和直观的代码示例,引领读者从理论到实践,体验进程与线程的魅力。我们将从基础概念出发,逐步深入到它们之间的联系与区别,最后探讨如何在编程实践中高效运用这些知识。无论你是初学者还是有经验的开发者,这篇文章都将为你的技术之旅增添新的航标。
|
13天前
|
Java 程序员 调度
【JAVA 并发秘籍】进程、线程、协程:揭秘并发编程的终极武器!
【8月更文挑战第25天】本文以问答形式深入探讨了并发编程中的核心概念——进程、线程与协程,并详细介绍了它们在Java中的应用。文章不仅解释了每个概念的基本原理及其差异,还提供了实用的示例代码,帮助读者理解如何在Java环境中实现这些并发机制。无论你是希望提高编程技能的专业开发者,还是准备技术面试的求职者,都能从本文获得有价值的见解。
31 1
|
11天前
|
数据采集 存储 安全
如何确保Python Queue的线程和进程安全性:使用锁的技巧
本文探讨了在Python爬虫技术中使用锁来保障Queue(队列)的线程和进程安全性。通过分析`queue.Queue`及`multiprocessing.Queue`的基本线程与进程安全特性,文章指出在特定场景下使用锁的重要性。文中还提供了一个综合示例,该示例利用亿牛云爬虫代理服务、多线程技术和锁机制,实现了高效且安全的网页数据采集流程。示例涵盖了代理IP、User-Agent和Cookie的设置,以及如何使用BeautifulSoup解析HTML内容并将其保存为文档。通过这种方式,不仅提高了数据采集效率,还有效避免了并发环境下的数据竞争问题。
如何确保Python Queue的线程和进程安全性:使用锁的技巧
|
9天前
|
调度
深入理解操作系统:进程与线程的管理
【8月更文挑战第29天】在数字世界的每一次点击和滑动背后,都隐藏着操作系统的精妙运作。本文将带你探索操作系统的核心概念之一——进程与线程的管理。我们将从基础定义出发,逐步深入到它们在内存中的表示、状态变迁以及它们之间错综复杂的关系。通过简洁明了的语言和直观的比喻,即便是没有计算机背景的读者也能轻松理解这一主题。准备好了吗?让我们一起揭开操作系统神秘的面纱,探索那些看似晦涩却无比精彩的知识吧!
|
11天前
|
调度 Python
深入理解操作系统:进程与线程的奥秘
【8月更文挑战第27天】本文将带你走进操作系统的核心,探索进程和线程这两个基本概念。我们将从它们的定义开始,逐步深入到它们之间的联系和区别,以及在操作系统中的作用。通过本文,你将了解到进程和线程不仅仅是编程中的两个术语,它们是操作系统管理资源、实现并发和并行的关键。最后,我们还将通过一个代码示例,展示如何在Python中创建和管理线程。
|
10天前
|
算法 调度 开发者
深入理解操作系统:进程与线程管理
【8月更文挑战第28天】在数字世界的心脏跳动着的是操作系统,它是计算机硬件与软件之间的桥梁。本文将带你探索操作系统的核心概念——进程与线程,揭示它们如何协同工作以支持多任务处理和并发执行。通过实际代码示例,我们将深入了解这些抽象概念是如何在真实系统中实现的。无论你是编程新手还是资深开发者,这篇文章都将为你提供新的视角,让你对操作系统有更深刻的认识。
|
14天前
|
Java Windows
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
【Azure Developer】Windows中通过pslist命令查看到Java进程和线程信息,但为什么和代码中打印出来的进程号不一致呢?
|
5天前
crash —— 输出属于同一个进程的所有线程
crash —— 输出属于同一个进程的所有线程
|
6天前
|
调度 开发者 Python
深入浅出操作系统:进程与线程的奥秘
【8月更文挑战第31天】 本文将带你探索操作系统中的核心概念——进程与线程。通过浅显易懂的语言和实际代码示例,我们将一起理解它们的定义、区别以及在操作系统中的作用。无论你是编程新手还是有一定经验的开发者,这篇文章都将为你打开一扇了解计算机内部工作原理的新窗口。
|
7天前
|
C# 开发者 数据处理
WPF开发者必备秘籍:深度解析数据网格最佳实践,轻松玩转数据展示与编辑大揭秘!
【8月更文挑战第31天】数据网格控件是WPF应用程序中展示和编辑数据的关键组件,提供排序、筛选等功能,显著提升用户体验。本文探讨WPF中数据网格的最佳实践,通过DevExpress DataGrid示例介绍其集成方法,包括添加引用、定义数据模型及XAML配置。通过遵循数据绑定、性能优化、自定义列等最佳实践,可大幅提升数据处理效率和用户体验。
22 0
下一篇
DDNS