Skip to content

Commit

Permalink
Merge branch 'feature/console_buffer_fetch' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
pippocao committed Aug 30, 2024
2 parents 788b1a4 + 2209f80 commit e028b20
Show file tree
Hide file tree
Showing 245 changed files with 6,863 additions and 5,599 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Changelog

## [v1.4.0] - 2023-08-03
- **First Release**

## [v1.4.1] - 2023-08-30
- **Console Buffer**: In addition to passively intercepting the output of console appenders through console callbacks, it is also possible to cache the output of console appenders through a console buffer and actively retrieve it via API.
- **Bug fix**: Fix the compiling issue with C++ 20.
- **Bug fix**: Fix the issue where JNI_Onload sometimes is not called.
34 changes: 31 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# BqLog(扁鹊日志)(V 1.4.0)
# BqLog(扁鹊日志)(V 1.4.1)
[![license](https://img.shields.io/badge/license-APACHE2.0-brightgreen.svg?style=flat)](https://github.com/Tencent/BqLog/blob/main/LICENSE.txt)
[![Release Version](https://img.shields.io/badge/release-1.4.0-red.svg)](https://github.com/Tencent/BqLog/releases)
[![Release Version](https://img.shields.io/badge/release-1.4.1-red.svg)](https://github.com/Tencent/BqLog/releases)
> [中文文档](./README_CHS.md)
> BqLog is a lightweight, high-performance logging system used in projects such as "Honor of Kings," and it has been successfully deployed and is running smoothly.
Expand Down Expand Up @@ -367,7 +367,35 @@ Since bqLog uses asynchronous logging by default, there are times when you might
/// <param name="callback"></param>
static void unregister_console_callback(bq::type_func_ptr_console_callback callback);
```
The output of[ConsoleAppender](#consoleappender) goes to the console or ADB Logcat logs on Android, but this may not cover all situations. For instance, in custom game engines or custom IDEs, a mechanism is provided to call a callback function for each console log output. This allows you to reprocess and output the console log anywhere in your program.
The output of[ConsoleAppender](#consoleappender) goes to the console or ADB Logcat logs on Android, but this may not cover all situations. For instance, in custom game engines or custom IDEs, a mechanism is provided to call a callback function for each console log output. This allows you to reprocess and output the console log anywhere in your program.
**Additional Caution:** Do not output any synchronized BQ logs within the console callback as it may easily lead to deadlocks.
#### Actively Fetching Console Output
```cpp
/// <summary>
/// Enable or disable the console appender buffer.
/// Since our wrapper may run in both C# and Java virtual machines, and we do not want to directly invoke callbacks from a native thread,
/// we can enable this option. This way, all console outputs will be saved in the buffer until we fetch them.
/// </summary>
/// <param name="enable"></param>
/// <returns></returns>
static void set_console_buffer_enable(bool enable);
/// <summary>
/// Fetch and remove a log entry from the console appender buffer in a thread-safe manner.
/// If the console appender buffer is not empty, the on_console_callback function will be invoked for this log entry.
/// Please ensure not to output synchronized BQ logs within the callback function.
/// </summary>
/// <param name="on_console_callback">A callback function to be invoked for the fetched log entry if the console appender buffer is not empty</param>
/// <returns>True if the console appender buffer is not empty and a log entry is fetched; otherwise False is returned.</returns>
static bool fetch_and_remove_console_buffer(bq::type_func_ptr_console_callback on_console_callback);
```
In addition to intercepting console output through a console callback, you can actively fetch console log outputs. Sometimes, we may not want the console log output to come through a callback because you do not know which thread the callback will come from (for example, in some C# virtual machines, or JVMs, the VM might be performing garbage collection when the console callback is called, which could potentially lead to hangs or crashes).

The method used here involves enabling the console buffer through `set_console_buffer_enable`. This causes every console log output to be stored in memory until we actively call `fetch_and_remove_console_buffer` to retrieve it. Therefore, if you choose to use this method, remember to promptly fetch and clear logs to avoid unreleased memory.
**Additional Caution:** Do not output any synchronized BQ logs within the console callback as it may easily lead to deadlocks.


#### Modifying Log Configuration
```cpp
Expand Down
30 changes: 28 additions & 2 deletions README_CHS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# BqLog(扁鹊日志)(V 1.4.0)
# BqLog(扁鹊日志)(V 1.4.1)
[![license](https://img.shields.io/badge/license-APACHE2.0-brightgreen.svg?style=flat)](https://github.com/Tencent/BqLog/blob/main/LICENSE.txt)
[![Release Version](https://img.shields.io/badge/release-1.4.0-red.svg)](https://github.com/Tencent/BqLog/releases)
[![Release Version](https://img.shields.io/badge/release-1.4.1-red.svg)](https://github.com/Tencent/BqLog/releases)
> BqLog是一个轻量级,高性能日志系统,应用于《Honor Of Kings》等项目,已经上线并良好运行
## 支持平台
Expand Down Expand Up @@ -369,6 +369,32 @@ STR参数类似于printf的第一个参数,其类型是各种常用类型的
static void unregister_console_callback(bq::type_func_ptr_console_callback callback);
```
[ConsoleAppender](#consoleappender)的输出是控制台,在android是ADB Logcat日志,但是这些无法涵盖所有的情况。比如自研游戏引擎,自研IDE等,这里提供了一种机制,可以让每一条console日志输出都调用一次参数里的回调,你可以在自己的程序里任意地方重新处理和输出这个控制台日志。
***注意:*** 不要在console callback中再去输出任何同步的扁鹊日志,不然很容易造成死锁
#### 主动获取console的输出
```cpp
/// <summary>
/// Enable or disable the console appender buffer.
/// Since our wrapper may run in both C# and Java virtual machines, and we do not want to directly invoke callbacks from a native thread,
/// we can enable this option. This way, all console outputs will be saved in the buffer until we fetch them.
/// </summary>
/// <param name="enable"></param>
/// <returns></returns>
static void set_console_buffer_enable(bool enable);
/// <summary>
/// Fetch and remove a log entry from the console appender buffer in a thread-safe manner.
/// If the console appender buffer is not empty, the on_console_callback function will be invoked for this log entry.
/// Please ensure not to output synchronized BQ logs within the callback function.
/// </summary>
/// <param name="on_console_callback">A callback function to be invoked for the fetched log entry if the console appender buffer is not empty</param>
/// <returns>True if the console appender buffer is not empty and a log entry is fetched; otherwise False is returned.</returns>
static bool fetch_and_remove_console_buffer(bq::type_func_ptr_console_callback on_console_callback);
```
除了用console callback去拦截console的输出之外,还可以通过主动调用去获取日志的console输出。有的时候,我们并不希望这个console的日志输出是通过callback调用过来的,因为你并不知道callback会通过什么线程过来(比如在C#的一些虚拟机,或者JVM中,console callback调用过来的时候,VM正在做GC,可能会发生卡死或者crash)。
这里采用的方法是通过`set_console_buffer_enable`先启用console的缓冲功能,每一条console日志输出都会被留在内存中,直到我们主动调用`fetch_and_remove_console_buffer`将它取出来。所以如果使用这种方法,请一定记得及时去获取和清理日志,不然内存会无法释放。
***注意:*** 不要在console callback中再去输出任何同步的扁鹊日志,不然很容易造成死锁


#### 修改log的配置
```cpp
Expand Down
Binary file modified dist/dynamic_lib/android/arm64-v8a/Debug/libBqLog.so
Binary file not shown.
Binary file modified dist/dynamic_lib/android/arm64-v8a/Debug/libBqLog_Symbol.so
Binary file not shown.
Binary file modified dist/dynamic_lib/android/arm64-v8a/MinSizeRel/libBqLog.so
Binary file not shown.
Binary file modified dist/dynamic_lib/android/arm64-v8a/MinSizeRel/libBqLog_Symbol.so
Binary file not shown.
Binary file modified dist/dynamic_lib/android/armeabi-v7a/Debug/libBqLog.so
Binary file not shown.
Binary file modified dist/dynamic_lib/android/armeabi-v7a/Debug/libBqLog_Symbol.so
Binary file not shown.
Binary file modified dist/dynamic_lib/android/armeabi-v7a/MinSizeRel/libBqLog.so
Binary file not shown.
Binary file not shown.
Binary file modified dist/dynamic_lib/android/x86_64/Debug/libBqLog.so
Binary file not shown.
Binary file modified dist/dynamic_lib/android/x86_64/Debug/libBqLog_Symbol.so
Binary file not shown.
Binary file modified dist/dynamic_lib/android/x86_64/MinSizeRel/libBqLog.so
Binary file not shown.
Binary file modified dist/dynamic_lib/android/x86_64/MinSizeRel/libBqLog_Symbol.so
Binary file not shown.
42 changes: 18 additions & 24 deletions dist/dynamic_lib/include/bq_common/types/array_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,26 +48,20 @@ namespace bq {
template <typename V, typename V_ARRAY>
BQ_ARRAY_ITER_CLS_NAME<T, ARRAY>& operator=(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs);

template <typename V, typename V_ARRAY>
bool operator==(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const;

template <typename V, typename V_ARRAY>
bool operator!=(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const;

template <typename V, typename V_ARRAY>
bool operator<(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const;

template <typename V, typename V_ARRAY>
bool operator<=(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const;

template <typename V, typename V_ARRAY>
bool operator>(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const;

template <typename V, typename V_ARRAY>
bool operator>=(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const;

template <typename V, typename V_ARRAY>
diff_type operator-(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const;
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
friend bool operator==(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2);
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
friend bool operator!=(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2);
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
friend bool operator<(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2);
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
friend bool operator<=(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2);
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
friend bool operator>(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2);
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
friend bool operator>=(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2);
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
friend typename BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>::diff_type operator-(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2);

BQ_ARRAY_ITER_CLS_NAME<T, ARRAY>& operator++();
BQ_ARRAY_ITER_CLS_NAME<T, ARRAY> operator++(int32_t);
Expand Down Expand Up @@ -133,11 +127,11 @@ namespace bq {

const value_type& operator[](size_type idx) const;

template <typename V, size_t CB>
bool operator==(const BQ_ARRAY_CLS_NAME<V, CB>& rhs);
template <typename T1, typename T2, size_t S1, size_t S2>
friend bool operator==(const BQ_ARRAY_CLS_NAME<T1, S1>& array1, const BQ_ARRAY_CLS_NAME<T2, S2>& array2);

template <typename V, size_t CB>
bool operator!=(const BQ_ARRAY_CLS_NAME<V, CB>& rhs);
template <typename T1, typename T2, size_t S1, size_t S2>
friend bool operator!=(const BQ_ARRAY_CLS_NAME<T1, S1>& array1, const BQ_ARRAY_CLS_NAME<T2, S2>& array2);

BQ_ARRAY_CLS_NAME<T, TAIL_BUFFER_SIZE>& operator=(const BQ_ARRAY_CLS_NAME<T, TAIL_BUFFER_SIZE>& rhs);

Expand Down
81 changes: 36 additions & 45 deletions dist/dynamic_lib/include/bq_common/types/array_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,60 +50,53 @@ namespace bq {
return *this;
}

template <typename T, typename ARRAY>
template <typename V, typename V_ARRAY>
BQ_ARRAY_INLINE bool BQ_ARRAY_ITER_CLS_NAME<T, ARRAY>::operator==(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
BQ_ARRAY_INLINE bool operator==(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2)
{
assert((array_data_ptr_ == rhs.array_data_ptr_) && "you can not compare two BQ_ARRAY_ITER_CLS_NAME generated from different BQ_ARRAY_CLS_NAME");
return data_ == rhs.operator->();
assert((array1.array_data_ptr_ == array2.array_data_ptr_) && "you can not compare two bq::array_iterator generated from different bq::array");
return array1.data_ == array2.data_;
}

template <typename T, typename ARRAY>
template <typename V, typename V_ARRAY>
BQ_ARRAY_INLINE bool BQ_ARRAY_ITER_CLS_NAME<T, ARRAY>::operator!=(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
BQ_ARRAY_INLINE bool operator!=(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2)
{
assert((array_data_ptr_ == rhs.array_data_ptr_) && "you can not compare two BQ_ARRAY_ITER_CLS_NAME generated from different BQ_ARRAY_CLS_NAME");
return data_ != rhs.operator->();
assert((array1.array_data_ptr_ == array2.array_data_ptr_) && "you can not compare two bq::array_iterator generated from different bq::array");
return array1.data_ != array2.data_;
}

template <typename T, typename ARRAY>
template <typename V, typename V_ARRAY>
BQ_ARRAY_INLINE bool BQ_ARRAY_ITER_CLS_NAME<T, ARRAY>::operator<(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
BQ_ARRAY_INLINE bool operator<(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2)
{
assert((array_data_ptr_ == rhs.array_data_ptr_) && "you can not compare two BQ_ARRAY_ITER_CLS_NAME generated from different BQ_ARRAY_CLS_NAME");
return data_ < rhs.operator->();
assert((array1.array_data_ptr_ == array2.array_data_ptr_) && "you can not compare two bq::array_iterator generated from different bq::array");
return array1.data_ < array2.data_;
}

template <typename T, typename ARRAY>
template <typename V, typename V_ARRAY>
BQ_ARRAY_INLINE bool BQ_ARRAY_ITER_CLS_NAME<T, ARRAY>::operator<=(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
BQ_ARRAY_INLINE bool operator<=(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2)
{
assert((array_data_ptr_ == rhs.array_data_ptr_) && "you can not compare two BQ_ARRAY_ITER_CLS_NAME generated from different BQ_ARRAY_CLS_NAME");
return data_ <= rhs.operator->();
assert((array1.array_data_ptr_ == array2.array_data_ptr_) && "you can not compare two bq::array_iterator generated from different bq::array");
return array1.data_ <= array2.data_;
}

template <typename T, typename ARRAY>
template <typename V, typename V_ARRAY>
BQ_ARRAY_INLINE bool BQ_ARRAY_ITER_CLS_NAME<T, ARRAY>::operator>(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
BQ_ARRAY_INLINE bool operator>(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2)
{
assert((array_data_ptr_ == rhs.array_data_ptr_) && "you can not compare two BQ_ARRAY_ITER_CLS_NAME generated from different BQ_ARRAY_CLS_NAME");
return data_ > rhs.operator->();
assert((array1.array_data_ptr_ == array2.array_data_ptr_) && "you can not compare two bq::array_iterator generated from different bq::array");
return array1.data_ > array2.data_;
}

template <typename T, typename ARRAY>
template <typename V, typename V_ARRAY>
BQ_ARRAY_INLINE bool BQ_ARRAY_ITER_CLS_NAME<T, ARRAY>::operator>=(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
BQ_ARRAY_INLINE bool operator>=(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2)
{
assert((array_data_ptr_ == rhs.array_data_ptr_) && "you can not compare two BQ_ARRAY_ITER_CLS_NAME generated from different BQ_ARRAY_CLS_NAME");
return data_ >= rhs.operator->();
assert((array1.array_data_ptr_ == array2.array_data_ptr_) && "you can not compare two bq::array_iterator generated from different bq::array");
return array1.data_ >= array2.data_;
}

template <typename T, typename ARRAY>
template <typename V, typename V_ARRAY>
BQ_ARRAY_INLINE typename BQ_ARRAY_ITER_CLS_NAME<T, ARRAY>::diff_type BQ_ARRAY_ITER_CLS_NAME<T, ARRAY>::operator-(const BQ_ARRAY_ITER_CLS_NAME<V, V_ARRAY>& rhs) const
template <typename T1, typename T2, typename V_ARRAY1, typename V_ARRAY2>
BQ_ARRAY_INLINE typename BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>::diff_type operator-(const BQ_ARRAY_ITER_CLS_NAME<T1, V_ARRAY1>& array1, const BQ_ARRAY_ITER_CLS_NAME<T2, V_ARRAY2>& array2)
{
assert((array_data_ptr_ == rhs.array_data_ptr_) && "you can not sub two BQ_ARRAY_ITER_CLS_NAME generated from different BQ_ARRAY_CLS_NAME");
return data_ - rhs.operator->();
assert((array1.array_data_ptr_ == array2.array_data_ptr_) && "you can not sub two bq::array_iterator generated from different bq::array");
return array1.data_ - array2.data_;
}

template <typename T, typename ARRAY>
Expand Down Expand Up @@ -315,26 +308,24 @@ namespace bq {
return data_[idx];
}

template <typename T, size_t TAIL_BUFFER_SIZE>
template <typename V, size_t CB>
BQ_ARRAY_INLINE bool BQ_ARRAY_CLS_NAME<T, TAIL_BUFFER_SIZE>::operator==(const BQ_ARRAY_CLS_NAME<V, CB>& rhs)
template <typename T1, typename T2, size_t S1, size_t S2>
BQ_ARRAY_INLINE bool operator==(const BQ_ARRAY_CLS_NAME<T1, S1>& array1, const BQ_ARRAY_CLS_NAME<T2, S2>& array2)
{
if (size_ != rhs.size_) {
if (array1.size() != array2.size()) {
return false;
}
for (size_type i = 0; i < size_; ++i) {
if (this->operator[](i) != rhs[i]) {
for (typename BQ_ARRAY_CLS_NAME<T1, S1>::size_type i = 0; i < array1.size(); ++i) {
if (array1[i] != array2[i]) {
return false;
}
}
return true;
}

template <typename T, size_t TAIL_BUFFER_SIZE>
template <typename V, size_t CB>
BQ_ARRAY_INLINE bool BQ_ARRAY_CLS_NAME<T, TAIL_BUFFER_SIZE>::operator!=(const BQ_ARRAY_CLS_NAME<V, CB>& rhs)
template <typename T1, typename T2, size_t S1, size_t S2>
BQ_ARRAY_INLINE bool operator!=(const BQ_ARRAY_CLS_NAME<T1, S1>& array1, const BQ_ARRAY_CLS_NAME<T2, S2>& array2)
{
return !operator==(rhs);
return !(array1 == array2);
}

template <typename T, size_t TAIL_BUFFER_SIZE>
Expand Down
Loading

0 comments on commit e028b20

Please sign in to comment.