神秘解密:stressapptest源码Logger日志操作深度剖析

这篇具有很好参考价值的文章主要介绍了神秘解密:stressapptest源码Logger日志操作深度剖析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、简介

stressapptest 是一个用于测试系统稳定性和可靠性的开源应用程序。它通过模拟在系统上运行的压力,并检查系统在这种严格条件下的稳定性。stressapptest 是一个非常有用的工具,可以在不同环境中对系统进行稳定性测试和故障排除。
stressapptest的log在哪里看,stressapptest源码剖析,c++,linux,stressapptest,内存测试,测试工具,压力测试,功能测试

二、logger头文件

Logger类的定义,它提供了日志记录的功能和相关操作。

#include <pthread.h>
#include <stdarg.h>

#include <string>
#include <vector>

#include "sattypes.h"

static const size_t kMaxQueueSize = 250;

#define LOGGER_ASSERT(x) \
{\
  if (!(x)) {\
    fprintf(stderr, "Assertion failed at %s:%d\n", __FILE__, __LINE__);\
    exit(1);\
  }\
}

class Logger {
 public:
  // Returns a pointer to the single global Logger instance.  Will not return
  // NULL.
  static Logger *GlobalLogger();

  // Lines with a priority numerically greater than this will not be logged.
  // May not be called while multiple threads are running.
  virtual void SetVerbosity(int verbosity) {
    verbosity_ = verbosity;
  }

  virtual void SetLogFd(int log_fd) {
    LOGGER_ASSERT(log_fd >= 0);
    log_fd_ = log_fd;
  }

  // Set output to be written to stdout only.  This is the default mode.  May
  // not be called while multiple threads are running.
  virtual void SetStdoutOnly() {
    log_fd_ = -1;
  }

  // Enable or disable logging of timestamps.
  void SetTimestampLogging(bool log_ts_enabled) {
    log_timestamps_ = log_ts_enabled;
  }
  void VLogF(int priority, const char *format, va_list args);

  void StartThread();
  
  void StopThread();

 protected:
  Logger();

  virtual ~Logger();

 private:
  // Args:
  //   line: Must be non-NULL.  This function takes ownership of it.
  void QueueLogLine(string *line);

  // Args:
  //   line: Must be non-NULL.  This function takes ownership of it.
  void WriteAndDeleteLogLine(string *line);

  // Callback for pthread_create(3).
  static void *StartRoutine(void *ptr);

  // Processes the log queue.
  void ThreadMain();

  pthread_t thread_;
  int verbosity_;
  int log_fd_;
  bool thread_running_;
  bool log_timestamps_;
  vector<string*> queued_lines_;
  // This doubles as a mutex for log_fd_ when the logging thread is not running.
  pthread_mutex_t queued_lines_mutex_;
  // Lets the logging thread know that the queue is no longer empty.
  pthread_cond_t queued_lines_cond_;
  // Lets the threads blocked on the queue having reached kMaxQueueSize know
  // that the queue has been emptied.
  pthread_cond_t full_queue_cond_;

  DISALLOW_COPY_AND_ASSIGN(Logger);
};

类的主要功能和细节:

  1. 提供了设置日志输出级别、写入文件描述符、启用时间戳记录等方法。
  2. 提供了启动和停止专用日志记录线程的方法。
  3. 提供了日志记录方法VLogF,它使用类似vprintf(3)的接口来记录日志,并可以阻塞等待将日志行写入stdout / disk,如果专用日志记录线程没有运行,则会阻塞将日志行添加到队列。
  4. 内部包含了一些用于管理日志记录队列和线程的成员变量,例如队列成员queued_lines_来存储日志行,还有互斥锁和条件变量用于线程同步。

三、Logger类的具体实现

  1. Logger 类设计为支持多线程环境,采用了互斥锁和条件变量进行线程同步控制,确保多线程情况下的安全访问。其中,QueueLogLine方法和ThreadMain方法中对互斥锁的使用尤为重要。

  2. 在方法QueueLogLine中,对line指针进行了判空处理,确保了line指针的有效性。在WriteAndDeleteLogLine方法中对line指针进行了删除操作,释放了内存资源。

  3. StartThread方法负责启动专用日志记录线程,StopThread方法负责终止线程。线程的启动和结束通过pthread_create和pthread_join来实现。

  4. 日志的时间戳记录和文件输出:VLogF方法负责记录日志,支持时间戳记录和分级别的日志输出。线程独立的日志记录功能由专用日志记录线程来实现,以提高效率。

  5. WriteAndDeleteLogLine方法中实现了向文件描述符和标准输出的写入操作。

  6. GlobalLogger方法通过静态局部变量实现了Logger类的单例模式,保证了全局只有一个Logger实例。

3.1、线程启动和结束

StartThread() 和StopThread()是Logger 类中用于启动和停止专用日志记录线程的函数实现。

void Logger::StartThread() {
  LOGGER_ASSERT(!thread_running_);
  thread_running_ = true;
  LOGGER_ASSERT(0 == pthread_create(&thread_, NULL, &StartRoutine, this));
}

void Logger::StopThread() {
  // Allow this to be called before the thread has started.
  if (!thread_running_) {
    return;
  }
  thread_running_ = false;
  int retval = pthread_mutex_lock(&queued_lines_mutex_);
  LOGGER_ASSERT(0 == retval);
  bool need_cond_signal = queued_lines_.empty();
  queued_lines_.push_back(NULL);
  retval = pthread_mutex_unlock(&queued_lines_mutex_);
  LOGGER_ASSERT(0 == retval);
  if (need_cond_signal) {
    retval = pthread_cond_signal(&queued_lines_cond_);
    LOGGER_ASSERT(0 == retval);
  }
  retval = pthread_join(thread_, NULL);
  LOGGER_ASSERT(0 == retval);
}

void *Logger::StartRoutine(void *ptr) {
  Logger *self = static_cast<Logger*>(ptr);
  self->ThreadMain();
  return NULL;
}

在 StartThread 方法中:

  • 首先,使用 LOGGER_ASSERT 断言检查线程是否已经在运行,如果已经运行则会触发断言失败;
  • 然后将 thread_running_ 标志设置为 true,表示线程已经启动;
  • 调用 pthread_create 函数创建日志记录线程,指定线程入口函数为 StartRoutine。

在 StopThread 方法中:

  • 首先判断如果线程没有运行,则直接返回,不做任何操作;
  • 将 thread_running_ 标志设置为 false,表示线程将要停止;
  • 对队列锁定互斥锁进行加锁,然后将一个空指针(NULL)放入队列中,用于通知线程退出;
  • 如果队列之前为空,需要发送条件信号给线程;
  • 然后使用 pthread_join 函数等待日志记录线程终止。

在这段代码中,使用了条件变量和互斥锁来实现线程的同步控制与通信。值得注意的是:

  • 在 StartThread 中,对 thread_running_ 的状态和 pthread_create 函数的调用使用断言确保了线程的正确启动;
  • 在 StopThread 中使用了 mutex 锁保护对队列的操作,并通过条件变量发送信号和使用 pthread_join 等待线程终止,确保了线程停止的安全操作。

3.2、QueueLogLine(string *)函数

主要是 Logger 类中用于处理队列日志行和写入日志的函数实现。使用了互斥锁和条件变量来实现线程同步控制与通信,保证了对队列的安全操作和日志写入的正确性。同时,在对指针进行相关操作时,使用断言进行合法性检查,确保了代码的稳定性和正确性。

void Logger::QueueLogLine(string *line) {
  LOGGER_ASSERT(line != NULL);
  LOGGER_ASSERT(0 == pthread_mutex_lock(&queued_lines_mutex_));
  if (thread_running_) {
    if (queued_lines_.size() >= kMaxQueueSize) {
      LOGGER_ASSERT(0 == pthread_cond_wait(&full_queue_cond_,
                                           &queued_lines_mutex_));
    }
    if (queued_lines_.empty()) {
      LOGGER_ASSERT(0 == pthread_cond_signal(&queued_lines_cond_));
    }
    queued_lines_.push_back(line);
  } else {
    WriteAndDeleteLogLine(line);
  }
  LOGGER_ASSERT(0 == pthread_mutex_unlock(&queued_lines_mutex_));
}

void Logger::WriteAndDeleteLogLine(string *line) {
  LOGGER_ASSERT(line != NULL);
  ssize_t bytes_written;
  if (log_fd_ >= 0) {
    bytes_written = write(log_fd_, line->data(), line->size());
    LOGGER_ASSERT(bytes_written == static_cast<ssize_t>(line->size()));
  }
  bytes_written = write(STDOUT_FILENO, line->data(), line->size());
  LOGGER_ASSERT(bytes_written == static_cast<ssize_t>(line->size()));
  delete line;
}

在 QueueLogLine 方法中:

  • 首先,使用 LOGGER_ASSERT 断言检查line指针的有效性,以及对互斥锁的加锁操作;
  • 然后判断线程是否正在运行,如果正在运行则将日志行加入队列,如果队列已满则通过条件变量 full_queue_cond 进行等待;
  • 如果队列为空,则通过条件变量 queued_lines_cond 发送信号;
  • 如果线程没有运行,则直接调用 WriteAndDeleteLogLine 方法进行日志写入操作;
  • 最后对互斥锁进行解锁操作。

在 WriteAndDeleteLogLine 方法中:

  • 首先,使用 LOGGER_ASSERT 断言检查line指针的有效性;
  • 然后根据 log_fd_ 是否大于等于0来判断是否需要向文件描述符写入数据,同时向标准输出写入相应内容;
  • 使用 write 函数将日志行写入文件描述符或者标准输出;
  • 最后删除日志行指针,释放内存资源。

3.3、记录日志信息的VLogF函数

void Logger::VLogF(int priority, const char *format, va_list args) {
  if (priority > verbosity_) {
    return;
  }
  char buffer[4096];
  size_t length = 0;
  if (log_timestamps_) {
    time_t raw_time;
    time(&raw_time);
    struct tm time_struct;
    localtime_r(&raw_time, &time_struct);
    length = strftime(buffer, sizeof(buffer), "%Y/%m/%d-%H:%M:%S(%Z) ",
                      &time_struct);
    LOGGER_ASSERT(length);  // Catch if the buffer is set too small.
  }
  length += vsnprintf(buffer + length, sizeof(buffer) - length, format, args);
  if (length >= sizeof(buffer)) {
    length = sizeof(buffer);
    buffer[sizeof(buffer) - 1] = '\n';
  }
  QueueLogLine(new string(buffer, length));
}

根据传入的日志优先级(priority)和日志输出级别(verbosity_)进行判断,如果priority大于verbosity_,则说明该日志信息不需要记录,直接返回。如果需要记录日志,则按照日志格式进行处理,并调用QueueLogLine方法将日志加入到日志队列中。

在方法实现中,具体的流程包括:

  • 首先对日志优先级进行判断,如果不满足条件则直接返回,不进行日志记录;
  • 然后根据log_timestamps_标志,判断是否需要输出时间戳,如果需要则获取当前时间并格式化为字符串,加入到日志内容中;
  • 调用vsnprintf函数将格式化后的日志内容加入到内部缓冲区buffer中;
  • 对日志内容的长度进行检查,如果超出了缓冲区的大小,进行限制,并补充一个换行符;
  • 最后调用QueueLogLine方法将带有日志内容的buffer加入到日志队列中。

流程图:

此实现使用了字符串格式化函数vsnprintf和时间格式化函数strftime,辅以合理的长度检查和条件判断,保证了日志信息处理的完整性和正确性。同时,使用QueueLogLine方法将日志加入队列,确保了多线程环境下的日志记录安全。

3.4、日志线程主循环ThreadMain()函数

该方法用于专门的日志记录线程的主要逻辑。

void Logger::ThreadMain() {
  vector<string*> local_queue;
  LOGGER_ASSERT(0 == pthread_mutex_lock(&queued_lines_mutex_));

  for (;;) {
    if (queued_lines_.empty()) {
      LOGGER_ASSERT(0 == pthread_cond_wait(&queued_lines_cond_,
                                           &queued_lines_mutex_));
      continue;
    }

    // We move the log lines into a local queue so we can release the lock
    // while writing them to disk, preventing other threads from blocking on
    // our writes.
    local_queue.swap(queued_lines_);
    if (local_queue.size() >= kMaxQueueSize) {
      LOGGER_ASSERT(0 == pthread_cond_broadcast(&full_queue_cond_));
    }

    // Unlock while we process our local queue.
    LOGGER_ASSERT(0 == pthread_mutex_unlock(&queued_lines_mutex_));
    for (vector<string*>::const_iterator it = local_queue.begin();
         it != local_queue.end(); ++it) {
      if (*it == NULL) {
        // NULL is guaranteed to be at the end.
        return;
      }
      WriteAndDeleteLogLine(*it);
    }
    local_queue.clear();
    // We must hold the lock at the start of each iteration of this for loop.
    LOGGER_ASSERT(0 == pthread_mutex_lock(&queued_lines_mutex_));
  }
}

主要包括以下流程:

  • 首先通过pthread_mutex_lock对队列的互斥锁进行加锁操作;
  • 之后使用一个无限循环,判断日志队列是否为空,如果为空则通过pthread_cond_wait进行等待,直到队列不再为空;
  • 当队列中有日志时,将日志行从全局队列中移动到本地队列local_queue,并在处理本地队列时释放全局锁,避免其他线程在日志写入期间阻塞;
  • 如果本地队列的大小超过了最大队列大小kMaxQueueSize,将通过pthread_cond_broadcast向所有等待的线程发出队列已满的信号;
  • 在处理本地队列时,遍历本地队列中的每个日志行,并对每一行进行写入操作,如果遇到空指针,则表明需要退出线程;
  • 清空本地队列,并在处理完后再次加锁全局队列的互斥锁。

流程图:

在流程图中,首先会判断queued_lines是否为空,如果队列不为空,则将日志行从全局队列中移动到本地队列。然后判断本地队列是否已满,如果已满则发送队列满信号,否则释放全局锁,然后对每行进行写入操作。最后清空本地队列并进行下一轮的循环。

该方法主要负责专门的日志记录线程的日志写入操作,并通过使用本地队列进行写入,从而避免了在写入过程中阻塞其他线程。同时,使用互斥锁和条件变量对线程进行了同步控制,确保了在多线程环境下的安全写入。

四、总结

分析了Logger类的一些关键方法和功能,包括启动和停止日志记录线程、日志队列操作、时间戳记录、日志行格式化、以及专门的日志记录线程逻辑。

Logger类提供了多线程环境下的高效日志记录功能,并且在设计上考虑了线程同步、异常处理以及内存管理等方面。它实现了多线程环境下的安全日志记录。

通过对每个方法的详细分析更好地理解这些方法的执行逻辑和线程之间的交互关系。这有助于我们深入理解和掌握Logger类的工作原理和功能。

stressapptest的log在哪里看,stressapptest源码剖析,c++,linux,stressapptest,内存测试,测试工具,压力测试,功能测试文章来源地址https://www.toymoban.com/news/detail-848827.html

到了这里,关于神秘解密:stressapptest源码Logger日志操作深度剖析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • rust库学习-env_logger(actix-web添加彩色日志、rust添加彩色日志 )

    我们在进行rust的web开发时,如果不指定日志,就不会有输出,非常不友好 这里我们使用 env_logger 进行日志打印 env_logger 需要配合 log 库使用, env_logger 是 Rust 社区中一个非常流行的日志记录库。它提供了一个简单且易于使用的接口,用于配置和记录日志消息。 env_logger 可以与

    2024年02月11日
    浏览(39)
  • Spring Boot日志:从Logger到@Slf4j的探秘

    写在前面 Hello大家好,今日是2024年的第一天,祝大家元旦快乐🎉 2024第一篇文章从 SpringBoot日志 开始 在我们日常的公司开发中,难免都会存在着大大小小的BUG,不可能会有公司说我们的项目做出来是没有BUG的,那既然或多或少会BUG的话,要如何去发现BUG呢? 那对于我们程序

    2024年02月03日
    浏览(48)
  • 解密Vue 3:透过原理看框架,揭开它的神秘面纱

    Vue 3 是一种用于 构建用户界面的现代 JavaScript 框架 。它基于 响应式编程 和 虚拟 DOM 技术 ,并通过 组件化 的方式来实现可重用的 UI 组件。 下面是 Vue 3 的主要原理: Vue 3 的核心是其响应式系统,它用于 追踪数据变化并使其自动更新 。Vue 3 使用 ES6 的 Proxy 对象来 实现监听

    2024年02月12日
    浏览(43)
  • 【Java 基础篇】Java类型通配符:解密泛型的神秘面纱

    在Java中,类型通配符(Type Wildcard)是泛型的重要概念之一。它使得我们能够更加灵活地处理泛型类型,使代码更通用且可复用。本文将深入探讨Java类型通配符的用法、语法和最佳实践。 类型通配符是一个用问号 ? 表示的通配符,它可以用于泛型类、方法和通配符边界。类型

    2024年02月07日
    浏览(51)
  • 【JWT】解密JWT:让您的Web应用程序更安全、更高效的神秘令牌

    接下来看看由辉辉所写的关于JWT+ElementUI的相关操作吧 目录 🥳🥳Welcome Huihui\\\'s Code World ! !🥳🥳 一.JWT是什么 JWT工作原理 JWT验证过程 JWT刷新 二.为什么要使用JWT 三.JWT如何使用【工具类】 四.案例演示【JWT的强大】  1.没有用jwt 2.用了jwt web.xml 过滤器(跨域问题) JWT验证过滤器

    2024年02月08日
    浏览(60)
  • 抖音seo源码-源代码开发搭建-开源部署操作日志

      抖音seo源码开发是一项非常重要的技术,在抖音上,有很多视频,如果你想让自己的视频脱颖而出,那么就需要优化自己的seo源码。不过,为了保护用户的隐私,抖音并不公开其seo算法的细节,因此需要开发者自己探索。抖音SEO矩阵系统源码开发功能模型是指在抖音平台上

    2024年02月13日
    浏览(49)
  • 深度揭秘JUnit5与Mockito的单元测试神秘面纱

    在今天的学习中,我们将深入研究 JUnit 和Mockito,这是 Java 开发中最强大的 单元测试 工具之一。通过学习如何编写清晰、高效的单元测试,我们将揭开单元测试的神秘面纱,助力你在项目中写出更健壮的代码。 提示: 今天的代码是在第九天代码的基础上进行开发,我们将为

    2024年02月02日
    浏览(58)
  • 华为鸿蒙系统:揭开全新操作系统的神秘面纱

    在全球科技竞争日益激烈的背景下,我国科技巨头华为公司自主研发了一款全新的操作系统——鸿蒙。这款操作系统旨在为华为自家设备提供强大的性能、安全性和智能化特性,以满足用户不断增长的需求。为了帮助广大开发者充分挖掘鸿蒙系统的巨大潜力,华为发布了一本

    2024年02月04日
    浏览(45)
  • Dubbo源码篇06---SPI神秘的面纱---原理篇---上

    上一篇文章,Dubbo源码篇05—SPI神秘的面纱—使用篇带领大家过了一遍Dubbo SPI的机制和使用,本文我们来深入Dubbo源码,一览背后原理。 本文基于: Dubbo SPI机制解析 一文而做,简化原文源码篇幅,加以图画解释。 随着服务化的推广,网站对Dubbo服务框架的需求逐渐增多,Dub

    2024年02月07日
    浏览(44)
  • 掌握Python文件操作的绝招:打造数据之径,揭开文件操作的神秘面纱

    我们应该都知道,我们日常使用的电脑和手机其实很多的操作对象都是文件,我们的键盘和屏幕也可以类似看成是文件,文件在我们的日常生活中起着非常大的作用,因为文件可以持久的存储数据。而作为学习 python 的我们来说,文件操作的学习也是必不可少的,那么今天我

    2024年02月13日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包