Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)
find_package(Backward CONFIG REQUIRED)
find_package(absl REQUIRED)
find_package(spdlog CONFIG REQUIRED)

# Find gperftools via pkg-config
find_package(PkgConfig REQUIRED)
Expand Down Expand Up @@ -98,11 +99,15 @@ set(PROFILER_SOURCES
src/symbolize.cpp
src/web_resources.cpp
src/web_server.cpp
src/internal/log_manager.cpp
src/internal/default_log_sink.cpp
)

set(PROFILER_HEADERS
include/profiler_manager.h
include/web_server.h
include/profiler/log_sink.h
include/profiler/logger.h
)

# Create library
Expand All @@ -116,6 +121,8 @@ target_link_libraries(profiler_lib
absl::stacktrace
absl::debugging_internal
absl::demangle_internal
spdlog::spdlog
Drogon::Drogon
pthread
${CMAKE_DL_LIBS}
PUBLIC
Expand Down Expand Up @@ -170,6 +177,17 @@ if(REMOTE_PROFILER_BUILD_TESTS)
)

add_test(NAME FullFlowTest COMMAND test_full_flow)

# Logger 测试
add_executable(test_logger tests/test_logger.cpp)
target_link_libraries(test_logger
profiler_lib
GTest::gtest
GTest::gtest_main
pthread
)

add_test(NAME LoggerTest COMMAND test_logger)
message(STATUS "Tests will be built")
else()
message(STATUS "Tests disabled")
Expand Down Expand Up @@ -199,6 +217,13 @@ if(REMOTE_PROFILER_INSTALL)
DESTINATION include/cpp-remote-profiler
)

# Install profiler subdirectory headers
install(FILES
include/profiler/log_sink.h
include/profiler/logger.h
DESTINATION include/cpp-remote-profiler/profiler
)

# Install version header
install(FILES include/version.h
DESTINATION include/cpp-remote-profiler
Expand Down
206 changes: 206 additions & 0 deletions docs/user_guide/02_api_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
## 目录
- [ProfilerManager](#profilermanager)
- [类型定义](#类型定义)
- [日志系统 API](#日志系统-api)
- [CPU Profiling API](#cpu-profiling-api)
- [Heap Profiling API](#heap-profiling-api)
- [线程堆栈 API](#线程堆栈-api)
Expand Down Expand Up @@ -75,6 +76,211 @@ struct ThreadStackTrace {

---

## 日志系统 API

profiler 库提供可配置的日志系统,允许用户将 profiler 的日志集成到自己的日志系统中。

### LogLevel

日志级别枚举。

```cpp
enum class LogLevel {
Trace, // 详细调试信息
Debug, // 调试信息
Info, // 一般信息(默认级别)
Warning, // 警告信息
Error, // 错误信息
Fatal // 致命错误
};
```

---

### LogSink

日志输出接口,用户可继承此类实现自定义日志输出。

```cpp
class LogSink {
public:
virtual ~LogSink() = default;

/// @brief 写入日志消息
/// @param level 日志级别
/// @param file 源文件名(可能为 nullptr)
/// @param line 源行号
/// @param function 函数名(可能为 nullptr)
/// @param message 格式化后的日志消息
virtual void log(LogLevel level,
const char* file,
int line,
const char* function,
const char* message) = 0;

/// @brief 刷新缓冲区(可选实现)
virtual void flush() {}
};
```

**说明**:
- 实现自定义 sink 后,通过 `setSink()` 注入到 profiler
- 设置自定义 sink 后,默认的 stderr 输出将被替换
- 所有参数的生命周期仅在 `log()` 调用期间有效,如需保留请复制

---

### setSink

设置自定义日志 sink。

```cpp
void setSink(std::shared_ptr<LogSink> sink);
```

**参数**:
- `sink`: 自定义 LogSink 的 shared_ptr,传 `nullptr` 恢复默认 sink

**说明**:
- 设置后,profiler 的所有日志将输出到自定义 sink
- 默认 sink 输出到 stderr(使用 spdlog)
- 设置 `nullptr` 可恢复默认行为

**示例**:
```cpp
#include <profiler/log_sink.h>
#include <profiler/logger.h>

// 自定义 sink:集成到应用日志系统
class MyAppLogSink : public profiler::LogSink {
public:
void log(profiler::LogLevel level, const char* file, int line,
const char* function, const char* message) override {
// 转发到应用的日志系统
switch (level) {
case profiler::LogLevel::Error:
MY_APP_ERROR("[Profiler] {}:{} - {}", file, line, message);
break;
case profiler::LogLevel::Warning:
MY_APP_WARN("[Profiler] {}:{} - {}", file, line, message);
break;
default:
MY_APP_INFO("[Profiler] {}:{} - {}", file, line, message);
break;
}
}
};

// 设置自定义 sink
profiler::setSink(std::make_shared<MyAppLogSink>());

// 恢复默认 sink
profiler::setSink(nullptr);
```

---

### setLogLevel

设置最小日志级别。

```cpp
void setLogLevel(LogLevel level);
```

**参数**:
- `level`: 最小日志级别,低于此级别的消息将被过滤

**说明**:
- 默认级别为 `LogLevel::Info`
- 日志级别从低到高:Trace < Debug < Info < Warning < Error < Fatal

**示例**:
```cpp
#include <profiler/logger.h>

// 启用调试日志
profiler::setLogLevel(profiler::LogLevel::Debug);

// 只显示错误和致命错误
profiler::setLogLevel(profiler::LogLevel::Error);

// 显示所有日志(包括 Trace)
profiler::setLogLevel(profiler::LogLevel::Trace);
```

---

### 完整示例:集成到 spdlog

```cpp
#include <profiler/log_sink.h>
#include <profiler/logger.h>
#include <spdlog/spdlog.h>

class SpdlogSink : public profiler::LogSink {
public:
void log(profiler::LogLevel level, const char* file, int line,
const char* function, const char* message) override {
// 映射日志级别
spdlog::level::level_enum spdlog_level;
switch (level) {
case profiler::LogLevel::Trace: spdlog_level = spdlog::level::trace; break;
case profiler::LogLevel::Debug: spdlog_level = spdlog::level::debug; break;
case profiler::LogLevel::Info: spdlog_level = spdlog::level::info; break;
case profiler::LogLevel::Warning: spdlog_level = spdlog::level::warn; break;
case profiler::LogLevel::Error: spdlog_level = spdlog::level::err; break;
case profiler::LogLevel::Fatal: spdlog_level = spdlog::level::critical; break;
}

// 输出到 spdlog
spdlog::log(spdlog::level::info, "[Profiler] {}:{} - {}", file, line, message);
}

void flush() override {
spdlog::default_logger()->flush();
}
};

int main() {
// 配置 spdlog
spdlog::set_level(spdlog::level::debug);
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S.%e] [%l] %v");

// 集成 profiler 日志到 spdlog
profiler::setSink(std::make_shared<SpdlogSink>());
profiler::setLogLevel(profiler::LogLevel::Debug);

// 使用 profiler...
}
```

---

### 完整示例:完全禁用日志

```cpp
#include <profiler/log_sink.h>
#include <profiler/logger.h>

// 空 sink:丢弃所有日志
class NullSink : public profiler::LogSink {
public:
void log(profiler::LogLevel, const char*, int,
const char*, const char*) override {
// 什么都不做
}
};

// 方法 1:使用空 sink
profiler::setSink(std::make_shared<NullSink>());

// 方法 2:设置日志级别为 Fatal(只显示致命错误)
profiler::setLogLevel(profiler::LogLevel::Fatal);
```

---

## CPU Profiling API

### startCPUProfiler
Expand Down
59 changes: 59 additions & 0 deletions include/profiler/log_sink.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/// @file log_sink.h
/// @brief Log sink interface for custom logging implementations

#pragma once

#include "profiler_version.h"
#include <string>

PROFILER_NAMESPACE_BEGIN

/// @enum LogLevel
/// @brief Log severity levels
enum class LogLevel {
Trace, ///< Detailed debug information
Debug, ///< Debug information
Info, ///< General information
Warning, ///< Warning messages
Error, ///< Error messages
Fatal ///< Fatal errors (typically terminates program)
};

/// @class LogSink
/// @brief Abstract interface for custom log output destinations
///
/// Users can inherit from this class to implement custom logging behavior,
/// such as integrating with their application's logging system.
///
/// @example
/// @code
/// class MyLogSink : public profiler::LogSink {
/// public:
/// void log(profiler::LogLevel level, const char* file, int line,
/// const char* function, const char* message) override {
/// // Forward to your application's logger
/// MyAppLogger::log(level, file, line, message);
/// }
/// };
///
/// // Set custom sink
/// profiler::setSink(std::make_shared<MyLogSink>());
/// @endcode
class LogSink {
public:
virtual ~LogSink() = default;

/// @brief Write a log message
/// @param level Log severity level
/// @param file Source file name (may be nullptr)
/// @param line Source line number
/// @param function Function name (may be nullptr)
/// @param message Formatted log message
virtual void log(LogLevel level, const char* file, int line, const char* function, const char* message) = 0;

/// @brief Flush any buffered log output
/// @note Default implementation does nothing
virtual void flush() {}
};

PROFILER_NAMESPACE_END
45 changes: 45 additions & 0 deletions include/profiler/logger.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/// @file logger.h
/// @brief Logger configuration interface

#pragma once

#include "log_sink.h"
#include <memory>

PROFILER_NAMESPACE_BEGIN

/// @brief Set a custom log sink for the profiler
/// @param sink Shared pointer to a LogSink implementation
///
/// When a custom sink is set, all profiler log messages will be
/// forwarded to this sink instead of the default output.
///
/// Pass nullptr to revert to the default sink.
///
/// @example
/// @code
/// // Use custom sink
/// profiler::setSink(std::make_shared<MyLogSink>());
///
/// // Revert to default
/// profiler::setSink(nullptr);
/// @endcode
void setSink(std::shared_ptr<LogSink> sink);

/// @brief Set the minimum log level
/// @param level Minimum level for messages to be output
///
/// Messages with a level lower than the specified level will be suppressed.
/// Default level is LogLevel::Info.
///
/// @example
/// @code
/// // Enable debug logging
/// profiler::setLogLevel(profiler::LogLevel::Debug);
///
/// // Suppress all but errors
/// profiler::setLogLevel(profiler::LogLevel::Error);
/// @endcode
void setLogLevel(LogLevel level);

PROFILER_NAMESPACE_END
Loading
Loading