Skip to content

Commit 2586237

Browse files
authored
Merge pull request #1 from Yimura/flush-queue
feat: Add class method to force the log queue to be flushed immediately
2 parents 8b0b5dc + 1ff5291 commit 2586237

4 files changed

Lines changed: 291 additions & 192 deletions

File tree

.clang-format

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
BasedOnStyle: Microsoft
2+
AccessModifierOffset: '-4'
3+
AlignAfterOpenBracket: DontAlign
4+
AlignConsecutiveAssignments: 'true'
5+
AlignEscapedNewlines: Left
6+
AlignOperands: 'false'
7+
AlignTrailingComments: 'true'
8+
AllowAllArgumentsOnNextLine: 'false'
9+
AllowAllConstructorInitializersOnNextLine: 'false'
10+
AllowAllParametersOfDeclarationOnNextLine: 'false'
11+
AllowShortBlocksOnASingleLine: 'false'
12+
AllowShortCaseLabelsOnASingleLine: 'true'
13+
AllowShortFunctionsOnASingleLine: None
14+
AllowShortIfStatementsOnASingleLine: Never
15+
AllowShortLambdasOnASingleLine: None
16+
AlwaysBreakAfterReturnType: None
17+
AlwaysBreakBeforeMultilineStrings: 'false'
18+
AlwaysBreakTemplateDeclarations: 'Yes'
19+
BinPackArguments: 'false'
20+
BinPackParameters: 'true'
21+
BreakBeforeBinaryOperators: NonAssignment
22+
BreakBeforeBraces: Allman
23+
BreakBeforeTernaryOperators: 'false'
24+
BreakConstructorInitializers: AfterColon
25+
BreakInheritanceList: AfterColon
26+
BreakStringLiterals: 'false'
27+
CompactNamespaces: 'false'
28+
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
29+
ConstructorInitializerIndentWidth: '4'
30+
Cpp11BracedListStyle: 'true'
31+
DerivePointerAlignment: 'false'
32+
FixNamespaceComments: 'false'
33+
IncludeBlocks: Regroup
34+
IndentCaseLabels: 'false'
35+
IndentPPDirectives: BeforeHash
36+
IndentWidth: '4'
37+
TabWidth: 4
38+
IndentWrappedFunctionNames: 'true'
39+
KeepEmptyLinesAtTheStartOfBlocks: 'false'
40+
Language: Cpp
41+
MacroBlockBegin: '0'
42+
MaxEmptyLinesToKeep: '2'
43+
NamespaceIndentation: All
44+
PenaltyExcessCharacter: '0'
45+
PenaltyReturnTypeOnItsOwnLine: '0'
46+
PointerAlignment: Left
47+
ReflowComments: 'false'
48+
SortIncludes: 'true'
49+
SortUsingDeclarations: 'true'
50+
SpaceAfterCStyleCast: 'false'
51+
SpaceAfterLogicalNot: 'false'
52+
SpaceAfterTemplateKeyword: 'false'
53+
SpaceBeforeAssignmentOperators: 'true'
54+
SpaceBeforeCpp11BracedList: 'false'
55+
SpaceBeforeCtorInitializerColon: 'true'
56+
SpaceBeforeInheritanceColon: 'true'
57+
SpaceBeforeParens: ControlStatements
58+
SpaceBeforeRangeBasedForLoopColon: 'true'
59+
SpaceInEmptyParentheses: 'false'
60+
SpacesBeforeTrailingComments: '1'
61+
SpacesInAngles: 'false'
62+
SpacesInCStyleCastParentheses: 'false'
63+
SpacesInContainerLiterals: 'false'
64+
SpacesInParentheses: 'false'
65+
SpacesInSquareBrackets: 'false'
66+
Standard: Auto
67+
UseTab: ForIndentation
68+
69+
BreakBeforeBraces: Custom
70+
BraceWrapping:
71+
BeforeLambdaBody: 'false'
72+
AfterCaseLabel: 'true'
73+
74+
PackConstructorInitializers: Never

CMakeLists.txt

Lines changed: 54 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,55 @@
1-
cmake_minimum_required(VERSION 3.20)
2-
3-
project(AsyncLogger LANGUAGES CXX VERSION 0.0.1 DESCRIPTION "A lightweight C++20 asyncronous logger.")
4-
5-
set(SRC_DIR "${PROJECT_SOURCE_DIR}/src")
6-
set(PUBLIC_HEADER_DIR "${PROJECT_SOURCE_DIR}/include")
7-
8-
# check std::format support
9-
if(NOT USE_FMT)
10-
include(CheckIncludeFileCXX)
11-
check_include_file_cxx("format" CXX_FORMAT_SUPPORT)
12-
else()
13-
set(CXX_FORMAT_SUPPORT 0)
14-
endif()
15-
16-
file(GLOB_RECURSE SRC_FILES
17-
"${SRC_DIR}/**.cpp"
18-
"${SRC_DIR}/**.hpp"
19-
)
20-
file(GLOB_RECURSE PUBLIC_HEADER_FILES
21-
"${PUBLIC_HEADER_DIR}/**.hpp"
22-
)
23-
24-
add_library(${PROJECT_NAME} STATIC ${SRC_FILES} ${PUBLIC_HEADER_FILES})
25-
26-
if(CXX_FORMAT_SUPPORT)
27-
message("Using std::format for formatting, you can set USE_FMT to force fmt::format instead.")
28-
else()
29-
message("Using fmt::format for formatting.")
30-
include(FetchContent)
31-
32-
FetchContent_Declare(
33-
fmt
34-
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
35-
GIT_TAG 9.1.0
36-
GIT_PROGRESS TRUE
37-
)
38-
FetchContent_MakeAvailable(fmt)
39-
40-
target_link_libraries(${PROJECT_NAME} fmt)
41-
endif()
42-
43-
# does the -lpthread linking for us on Linux
44-
find_package(Threads REQUIRED)
45-
target_link_libraries(${PROJECT_NAME} Threads::Threads )
46-
47-
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
48-
49-
target_include_directories(${PROJECT_NAME} PRIVATE "${PUBLIC_HEADER_DIR}/AsyncLogger/")
50-
target_include_directories(${PROJECT_NAME} PUBLIC "${SRC_DIR}")
51-
target_precompile_headers(${PROJECT_NAME} PRIVATE "${SRC_DIR}/common.hpp")
52-
53-
# public stuff
54-
set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADER_FILES}")
1+
cmake_minimum_required(VERSION 3.20)
2+
3+
project(AsyncLogger LANGUAGES CXX VERSION 0.0.1 DESCRIPTION "A lightweight C++20 asyncronous logger.")
4+
5+
set(SRC_DIR "${PROJECT_SOURCE_DIR}/src")
6+
set(PUBLIC_HEADER_DIR "${PROJECT_SOURCE_DIR}/include")
7+
8+
# check std::format support
9+
if(NOT USE_FMT)
10+
include(CheckIncludeFileCXX)
11+
check_include_file_cxx("format" CXX_FORMAT_SUPPORT)
12+
else()
13+
set(CXX_FORMAT_SUPPORT 0)
14+
endif()
15+
16+
file(GLOB_RECURSE SRC_FILES
17+
"${SRC_DIR}/**.cpp"
18+
"${SRC_DIR}/**.hpp"
19+
)
20+
file(GLOB_RECURSE PUBLIC_HEADER_FILES
21+
"${PUBLIC_HEADER_DIR}/**.hpp"
22+
)
23+
24+
add_library(${PROJECT_NAME} STATIC ${SRC_FILES} ${PUBLIC_HEADER_FILES})
25+
26+
if(CXX_FORMAT_SUPPORT)
27+
message(STATUS "Using std::format for formatting, you can set USE_FMT to force fmt::format instead.")
28+
else()
29+
message(STATUS "Using fmt::format for formatting.")
30+
include(FetchContent)
31+
32+
FetchContent_Declare(
33+
fmt
34+
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
35+
GIT_TAG 9.1.0
36+
GIT_PROGRESS TRUE
37+
)
38+
FetchContent_MakeAvailable(fmt)
39+
40+
target_link_libraries(${PROJECT_NAME} fmt)
41+
endif()
42+
43+
# does the -lpthread linking for us on Linux
44+
find_package(Threads REQUIRED)
45+
target_link_libraries(${PROJECT_NAME} Threads::Threads )
46+
47+
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)
48+
49+
target_include_directories(${PROJECT_NAME} PRIVATE "${PUBLIC_HEADER_DIR}/AsyncLogger/")
50+
target_include_directories(${PROJECT_NAME} PUBLIC "${SRC_DIR}")
51+
target_precompile_headers(${PROJECT_NAME} PRIVATE "${SRC_DIR}/common.hpp")
52+
53+
# public stuff
54+
set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADER_FILES}")
5555
target_include_directories(${PROJECT_NAME} PUBLIC "${PUBLIC_HEADER_DIR}")

include/AsyncLogger/Logger.hpp

Lines changed: 75 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,76 @@
1-
#pragma once
2-
#ifndef USE_FMT
3-
#include <format>
4-
#define FORMAT std::format
5-
#define VFORMAT std::vformat
6-
#define MAKE_FORMAT_ARGS std::make_format_args
7-
#else
8-
#include <fmt/core.h>
9-
#define FORMAT fmt::format
10-
#define VFORMAT fmt::vformat
11-
#define MAKE_FORMAT_ARGS fmt::make_format_args
12-
#endif
13-
#include <functional>
14-
#include "concurrency/shared_queue.hpp"
15-
#include "LogCapture.hpp"
16-
#include "LogIntermediate.hpp"
17-
#include "LogLevel.hpp"
18-
#include "LogMessage.hpp"
19-
20-
namespace al
21-
{
22-
using LogMessagePtr = std::shared_ptr<LogMessage>;
23-
using LogSink = std::function<void(LogMessagePtr)>;
24-
25-
class Logger
26-
{
27-
public:
28-
Logger() = default;
29-
virtual ~Logger() = default;
30-
31-
static void AddSink(LogSink sink);
32-
static void Destroy();
33-
static void Init();
34-
35-
protected:
36-
static void PushMessage(const eLogLevel level, std::chrono::system_clock::time_point&& timestamp, std::source_location&& location, std::string&& message) noexcept;
37-
38-
private:
39-
void CallSinks(LogMessagePtr msgPtr);
40-
void DestroyImpl();
41-
void InitImpl();
42-
void QueueMessage(LogMessagePtr msgPtr);
43-
44-
static Logger& GetInstance()
45-
{
46-
static Logger i{};
47-
return i;
48-
}
49-
50-
private:
51-
friend LogCapture::~LogCapture();
52-
53-
shared_queue<std::function<void()>> m_Queue;
54-
std::vector<LogSink> m_Sinks;
55-
bool m_Running = false;
56-
std::thread m_LogWorker;
57-
58-
};
59-
60-
extern LogCapture LOG(const eLogLevel level, std::source_location location = std::source_location::current());
61-
62-
template<typename ...Args>
63-
inline void LOGF(const eLogLevel level, LogIntermediate formatString, Args&&... formatArgs)
64-
{
65-
auto capture = LogCapture(level, std::move(formatString.Location()));
66-
capture << VFORMAT(formatString.FormatString(), MAKE_FORMAT_ARGS(std::forward<Args>(formatArgs)...));
67-
}
1+
#pragma once
2+
#ifndef USE_FMT
3+
#include <format>
4+
#define FORMAT std::format
5+
#define VFORMAT std::vformat
6+
#define MAKE_FORMAT_ARGS std::make_format_args
7+
#else
8+
#include <fmt/core.h>
9+
#define FORMAT fmt::format
10+
#define VFORMAT fmt::vformat
11+
#define MAKE_FORMAT_ARGS fmt::make_format_args
12+
#endif
13+
#include <functional>
14+
#include "concurrency/shared_queue.hpp"
15+
#include "LogCapture.hpp"
16+
#include "LogIntermediate.hpp"
17+
#include "LogLevel.hpp"
18+
#include "LogMessage.hpp"
19+
20+
namespace al
21+
{
22+
using LogMessagePtr = std::shared_ptr<LogMessage>;
23+
using LogSink = std::function<void(LogMessagePtr)>;
24+
25+
class Logger
26+
{
27+
public:
28+
Logger() = default;
29+
virtual ~Logger() = default;
30+
31+
static void AddSink(LogSink sink);
32+
static void Destroy();
33+
static void Init();
34+
/**
35+
* @brief Attempts to flush the log queue immediately until it's completely empty.
36+
*/
37+
static void FlushQueue();
38+
39+
protected:
40+
static void PushMessage(const eLogLevel level, std::chrono::system_clock::time_point&& timestamp, std::source_location&& location, std::string&& message) noexcept;
41+
42+
private:
43+
void CallSinks(LogMessagePtr msgPtr);
44+
void DestroyImpl();
45+
void InitImpl();
46+
/**
47+
* @brief Attempts to flush the entire log queue before returning
48+
*/
49+
void FlushQueueImpl();
50+
void QueueMessage(LogMessagePtr msgPtr);
51+
52+
static Logger& GetInstance()
53+
{
54+
static Logger i{};
55+
return i;
56+
}
57+
58+
private:
59+
friend LogCapture::~LogCapture();
60+
61+
shared_queue<std::function<void()>> m_Queue;
62+
std::vector<LogSink> m_Sinks;
63+
bool m_Running = false;
64+
std::thread m_LogWorker;
65+
66+
};
67+
68+
extern LogCapture LOG(const eLogLevel level, std::source_location location = std::source_location::current());
69+
70+
template<typename ...Args>
71+
inline void LOGF(const eLogLevel level, LogIntermediate formatString, Args&&... formatArgs)
72+
{
73+
auto capture = LogCapture(level, std::move(formatString.Location()));
74+
capture << VFORMAT(formatString.FormatString(), MAKE_FORMAT_ARGS(std::forward<Args>(formatArgs)...));
75+
}
6876
}

0 commit comments

Comments
 (0)