Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
S
spdlog
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
spdlog
Commits
a96b4d75
Commit
a96b4d75
authored
Jul 21, 2018
by
gabime
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added periodic flusher support, and fixed some registry issues
parent
d5af87a8
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
134 additions
and
58 deletions
+134
-58
README.md
README.md
+11
-0
example.cpp
example/example.cpp
+10
-2
example.sln
example/example.sln
+3
-14
example.vcxproj
example/example.vcxproj
+3
-3
async.h
include/spdlog/async.h
+7
-3
registry.h
include/spdlog/details/registry.h
+38
-15
spdlog.h
include/spdlog/spdlog.h
+8
-0
test_async.cpp
tests/test_async.cpp
+36
-20
test_misc.cpp
tests/test_misc.cpp
+17
-0
tests.vcxproj
tests/tests.vcxproj
+1
-1
No files found.
README.md
View file @
a96b4d75
...
...
@@ -145,6 +145,7 @@ void rotating_example()
auto
rotating_logger
=
spdlog
::
rotating_logger_mt
(
"some_logger_name"
,
"logs/rotating.txt"
,
1048576
*
5
,
3
);
}
```
---
#### Daily files
```
c++
...
...
@@ -157,6 +158,16 @@ void daily_example()
}
```
---
#### Periodic flush
```
c++
// periodically flush all *registered* loggers every 3 seconds:
// warning: only use if all your loggers are thread safe!
spdlog
::
flush_every
(
std
::
chrono
::
seconds
(
3
));
```
---
#### Asynchronous logging
```
c++
...
...
example/example.cpp
View file @
a96b4d75
...
...
@@ -45,8 +45,14 @@ int main(int, char *[])
// custom error handler
err_handler_example
();
// flush all *registered* loggers using a worker thread every 3 seconds.
// note: registered loggers *must* be thread safe for this to work correctly!
spdlog
::
flush_every
(
std
::
chrono
::
seconds
(
3
));
// apply some function on all registered loggers
spdlog
::
apply_all
([
&
](
std
::
shared_ptr
<
spdlog
::
logger
>
l
)
{
l
->
info
(
"End of example."
);
});
spdlog
::
apply_all
([
&
](
std
::
shared_ptr
<
spdlog
::
logger
>
l
)
{
l
->
info
(
"End of example."
);
});
// Release and close all loggers
spdlog
::
drop_all
();
...
...
@@ -172,7 +178,9 @@ void user_defined_example()
void
err_handler_example
()
{
// can be set globally or per logger(logger->set_error_handler(..))
spdlog
::
set_error_handler
([](
const
std
::
string
&
msg
)
{
spdlog
::
get
(
"console"
)
->
error
(
"*** ERROR HANDLER EXAMPLE ***: {}"
,
msg
);
});
spdlog
::
set_error_handler
([](
const
std
::
string
&
msg
)
{
spdlog
::
get
(
"console"
)
->
error
(
"*** ERROR HANDLER EXAMPLE ***: {}"
,
msg
);
});
spdlog
::
get
(
"console"
)
->
info
(
"some invalid message to trigger an error {}{}{}{}"
,
3
);
}
...
...
example/example.sln
View file @
a96b4d75
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio
15
VisualStudioVersion = 1
5.0.27428.2037
# Visual Studio
2013
VisualStudioVersion = 1
2.0.40629.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example", "example.vcxproj", "{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}"
EndProject
...
...
@@ -29,6 +29,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "details", "details", "{08E9
..\include\spdlog\details\null_mutex.h = ..\include\spdlog\details\null_mutex.h
..\include\spdlog\details\os.h = ..\include\spdlog\details\os.h
..\include\spdlog\details\pattern_formatter.h = ..\include\spdlog\details\pattern_formatter.h
..\include\spdlog\details\periodic_worker.h = ..\include\spdlog\details\periodic_worker.h
..\include\spdlog\details\registry.h = ..\include\spdlog\details\registry.h
..\include\spdlog\details\spdlog_impl.h = ..\include\spdlog\details\spdlog_impl.h
..\include\spdlog\details\thread_pool.h = ..\include\spdlog\details\thread_pool.h
...
...
@@ -101,16 +102,4 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1BF53532-C5DC-4236-B195-9E17CBE40A48}
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal
example/example.vcxproj
View file @
a96b4d75
...
...
@@ -31,7 +31,7 @@
<PropertyGroup
Condition=
"'$(Configuration)|$(Platform)'=='Debug|Win32'"
Label=
"Configuration"
>
<ConfigurationType>
Application
</ConfigurationType>
<UseDebugLibraries>
true
</UseDebugLibraries>
<PlatformToolset>
v1
41
</PlatformToolset>
<PlatformToolset>
v1
20
</PlatformToolset>
<CharacterSet>
Unicode
</CharacterSet>
</PropertyGroup>
<PropertyGroup
Condition=
"'$(Configuration)|$(Platform)'=='Debug|x64'"
Label=
"Configuration"
>
...
...
@@ -43,7 +43,7 @@
<PropertyGroup
Condition=
"'$(Configuration)|$(Platform)'=='Release|Win32'"
Label=
"Configuration"
>
<ConfigurationType>
Application
</ConfigurationType>
<UseDebugLibraries>
false
</UseDebugLibraries>
<PlatformToolset>
v1
41
</PlatformToolset>
<PlatformToolset>
v1
20
</PlatformToolset>
<WholeProgramOptimization>
true
</WholeProgramOptimization>
<CharacterSet>
Unicode
</CharacterSet>
</PropertyGroup>
...
...
@@ -86,7 +86,7 @@
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>
Level
3
</WarningLevel>
<WarningLevel>
Level
4
</WarningLevel>
<Optimization>
Disabled
</Optimization>
<PreprocessorDefinitions>
WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)
</PreprocessorDefinitions>
<AdditionalIncludeDirectories>
..\include;%(AdditionalIncludeDirectories)
</AdditionalIncludeDirectories>
...
...
include/spdlog/async.h
View file @
a96b4d75
...
...
@@ -19,8 +19,12 @@
#include "spdlog/details/thread_pool.h"
#include <memory>
namespace
spdlog
{
namespace
details
{
static
const
size_t
default_async_q_size
=
8192
;
}
// async logger factory - creates async loggers backed with thread pool.
// if a global thread pool doesn't already exist, create it with default queue size of 8192 items and single thread.
...
...
@@ -32,11 +36,11 @@ struct async_factory_impl
{
using
details
::
registry
;
std
::
lock_guard
<
registry
::
MutexT
>
lock
(
registry
::
instance
().
tp_mutex
());
std
::
lock_guard
<
std
::
recursive_mutex
>
lock
(
registry
::
instance
().
tp_mutex
());
auto
tp
=
registry
::
instance
().
get_thread_pool
();
if
(
tp
==
nullptr
)
{
tp
=
std
::
make_shared
<
details
::
thread_pool
>
(
8192
,
1
);
tp
=
std
::
make_shared
<
details
::
thread_pool
>
(
details
::
default_async_q_size
,
1
);
registry
::
instance
().
set_thread_pool
(
tp
);
}
...
...
@@ -62,7 +66,7 @@ inline std::shared_ptr<spdlog::logger> create_async_nb(const std::string &logger
{
return
async_factory_nonblock
::
create
<
Sink
>
(
logger_name
,
std
::
forward
<
SinkArgs
>
(
sink_args
)...);
}
// set global thread pool.
inline
void
init_thread_pool
(
size_t
q_size
,
size_t
thread_count
)
...
...
include/spdlog/details/registry.h
View file @
a96b4d75
...
...
@@ -12,6 +12,7 @@
#include "spdlog/common.h"
#include "spdlog/logger.h"
#include "spdlog/details/periodic_worker.h"
#include <chrono>
#include <functional>
...
...
@@ -34,7 +35,7 @@ public:
void
register_logger
(
std
::
shared_ptr
<
logger
>
new_logger
)
{
std
::
lock_guard
<
Mutex
>
lock
(
mutex_
);
std
::
lock_guard
<
Mutex
>
lock
(
loggers_
mutex_
);
auto
logger_name
=
new_logger
->
name
();
throw_if_exists_
(
logger_name
);
loggers_
[
logger_name
]
=
new_logger
;
...
...
@@ -42,7 +43,7 @@ public:
void
register_and_init
(
std
::
shared_ptr
<
logger
>
new_logger
)
{
std
::
lock_guard
<
Mutex
>
lock
(
mutex_
);
std
::
lock_guard
<
Mutex
>
lock
(
loggers_
mutex_
);
auto
logger_name
=
new_logger
->
name
();
throw_if_exists_
(
logger_name
);
...
...
@@ -63,26 +64,26 @@ public:
std
::
shared_ptr
<
logger
>
get
(
const
std
::
string
&
logger_name
)
{
std
::
lock_guard
<
Mutex
>
lock
(
mutex_
);
std
::
lock_guard
<
Mutex
>
lock
(
loggers_
mutex_
);
auto
found
=
loggers_
.
find
(
logger_name
);
return
found
==
loggers_
.
end
()
?
nullptr
:
found
->
second
;
}
void
set_thread_pool
(
std
::
shared_ptr
<
thread_pool
>
tp
)
{
std
::
lock_guard
<
Mutex
>
lock
(
mutex_
);
std
::
lock_guard
<
decltype
(
tp_mutex_
)
>
lock
(
tp_
mutex_
);
tp_
=
std
::
move
(
tp
);
}
std
::
shared_ptr
<
thread_pool
>
get_thread_pool
()
{
std
::
lock_guard
<
Mutex
>
lock
(
mutex_
);
std
::
lock_guard
<
decltype
(
tp_mutex_
)
>
lock
(
tp_
mutex_
);
return
tp_
;
}
void
set_pattern
(
const
std
::
string
&
pattern
,
pattern_time_type
time_type
)
{
std
::
lock_guard
<
Mutex
>
lock
(
mutex_
);
std
::
lock_guard
<
Mutex
>
lock
(
loggers_
mutex_
);
formatter_pattern_
=
pattern
;
pattern_time_type_
=
time_type
;
for
(
auto
&
l
:
loggers_
)
...
...
@@ -93,7 +94,7 @@ public:
void
set_level
(
level
::
level_enum
log_level
)
{
std
::
lock_guard
<
Mutex
>
lock
(
mutex_
);
std
::
lock_guard
<
Mutex
>
lock
(
loggers_
mutex_
);
for
(
auto
&
l
:
loggers_
)
{
l
.
second
->
set_level
(
log_level
);
...
...
@@ -103,7 +104,7 @@ public:
void
flush_on
(
level
::
level_enum
log_level
)
{
std
::
lock_guard
<
Mutex
>
lock
(
mutex_
);
std
::
lock_guard
<
Mutex
>
lock
(
loggers_
mutex_
);
for
(
auto
&
l
:
loggers_
)
{
l
.
second
->
flush_on
(
log_level
);
...
...
@@ -111,6 +112,13 @@ public:
flush_level_
=
log_level
;
}
void
flush_every
(
std
::
chrono
::
seconds
interval
)
{
std
::
lock_guard
<
Mutex
>
lock
(
loggers_mutex_
);
std
::
function
<
void
()
>
clbk
(
std
::
bind
(
&
registry_t
::
flush_all
,
this
));
periodic_flusher_
.
reset
(
new
periodic_worker
(
clbk
,
interval
));
}
void
set_error_handler
(
log_err_handler
handler
)
{
for
(
auto
&
l
:
loggers_
)
...
...
@@ -122,7 +130,7 @@ public:
void
apply_all
(
std
::
function
<
void
(
std
::
shared_ptr
<
logger
>
)
>
fun
)
{
std
::
lock_guard
<
Mutex
>
lock
(
mutex_
);
std
::
lock_guard
<
Mutex
>
lock
(
loggers_
mutex_
);
for
(
auto
&
l
:
loggers_
)
{
fun
(
l
.
second
);
...
...
@@ -131,24 +139,24 @@ public:
void
drop
(
const
std
::
string
&
logger_name
)
{
std
::
lock_guard
<
Mutex
>
lock
(
mutex_
);
std
::
lock_guard
<
Mutex
>
lock
(
loggers_
mutex_
);
loggers_
.
erase
(
logger_name
);
}
void
drop_all
()
{
{
std
::
lock_guard
<
Mutex
>
lock
(
mutex_
);
std
::
lock_guard
<
Mutex
>
lock
(
loggers_
mutex_
);
loggers_
.
clear
();
}
{
std
::
lock_guard
<
Mutex
>
lock
(
tp_mutex_
);
std
::
lock_guard
<
decltype
(
tp_mutex_
)
>
lock
(
tp_mutex_
);
tp_
.
reset
();
}
}
M
utex
&
tp_mutex
()
std
::
recursive_m
utex
&
tp_mutex
()
{
return
tp_mutex_
;
}
...
...
@@ -162,6 +170,11 @@ public:
private
:
registry_t
<
Mutex
>
()
=
default
;
~
registry_t
<
Mutex
>
()
{
periodic_flusher_
.
reset
();
}
void
throw_if_exists_
(
const
std
::
string
&
logger_name
)
{
if
(
loggers_
.
find
(
logger_name
)
!=
loggers_
.
end
())
...
...
@@ -170,8 +183,17 @@ private:
}
}
Mutex
mutex_
;
Mutex
tp_mutex_
;
void
flush_all
()
{
std
::
lock_guard
<
Mutex
>
lock
(
loggers_mutex_
);
for
(
auto
&
l
:
loggers_
)
{
l
.
second
->
flush
();
}
}
Mutex
loggers_mutex_
;
std
::
recursive_mutex
tp_mutex_
;
std
::
unordered_map
<
std
::
string
,
std
::
shared_ptr
<
logger
>>
loggers_
;
std
::
string
formatter_pattern_
=
"%+"
;
pattern_time_type
pattern_time_type_
=
pattern_time_type
::
local
;
...
...
@@ -179,6 +201,7 @@ private:
level
::
level_enum
flush_level_
=
level
::
off
;
log_err_handler
err_handler_
;
std
::
shared_ptr
<
thread_pool
>
tp_
;
std
::
unique_ptr
<
periodic_worker
>
periodic_flusher_
;
};
#ifdef SPDLOG_NO_REGISTRY_MUTEX
...
...
include/spdlog/spdlog.h
View file @
a96b4d75
...
...
@@ -71,6 +71,14 @@ inline void flush_on(level::level_enum log_level)
details
::
registry
::
instance
().
flush_on
(
log_level
);
}
// Start/Restart a periodic flusher thread
// Warning: Use only if all your loggers are thread safe!
inline
void
flush_every
(
std
::
chrono
::
seconds
interval
)
{
details
::
registry
::
instance
().
flush_every
(
interval
);
}
// Set global error handler
inline
void
set_error_handler
(
log_err_handler
handler
)
{
...
...
tests/test_async.cpp
View file @
a96b4d75
...
...
@@ -27,34 +27,34 @@ TEST_CASE("discard policy ", "[async]")
using
namespace
spdlog
;
auto
test_sink
=
std
::
make_shared
<
sinks
::
test_sink_mt
>
();
size_t
queue_size
=
2
;
size_t
messages
=
1024
;
size_t
messages
=
10240
;
auto
tp
=
std
::
make_shared
<
details
::
thread_pool
>
(
queue_size
,
1
);
auto
logger
=
std
::
make_shared
<
async_logger
>
(
"as"
,
test_sink
,
tp
,
async_overflow_policy
::
overrun_oldest
);
for
(
size_t
i
=
0
;
i
<
messages
;
i
++
)
{
auto
tp
=
std
::
make_shared
<
details
::
thread_pool
>
(
queue_size
,
1
);
auto
logger
=
std
::
make_shared
<
async_logger
>
(
"as"
,
test_sink
,
tp
,
async_overflow_policy
::
overrun_oldest
);
for
(
size_t
i
=
0
;
i
<
messages
;
i
++
)
{
logger
->
info
(
"Hello message #{}"
,
i
);
}
logger
->
info
(
"Hello message"
);
}
REQUIRE
(
test_sink
->
msg_counter
()
<
messages
);
}
TEST_CASE
(
"discard policy using factory "
,
"[async]"
)
{
using
namespace
spdlog
;
//auto test_sink = std::make_shared<sinks::test_sink_mt>();
size_t
queue_size
=
2
;
size_t
messages
=
1024
;
{
auto
logger
=
spdlog
::
create_async_nb
<
sinks
::
test_sink_mt
>
(
"as2"
);
for
(
size_t
i
=
0
;
i
<
messages
;
i
++
)
{
logger
->
info
(
"Hello message #{}"
,
i
);
}
auto
sink
=
std
::
static_pointer_cast
<
sinks
::
test_sink_mt
>
(
logger
->
sinks
()[
0
]);
REQUIRE
(
sink
->
msg_counter
()
<
messages
);
}
size_t
messages
=
10240
;
spdlog
::
init_thread_pool
(
queue_size
,
1
);
auto
logger
=
spdlog
::
create_async_nb
<
sinks
::
test_sink_mt
>
(
"as2"
);
for
(
size_t
i
=
0
;
i
<
messages
;
i
++
)
{
logger
->
info
(
"Hello message"
);
}
auto
sink
=
std
::
static_pointer_cast
<
sinks
::
test_sink_mt
>
(
logger
->
sinks
()[
0
]);
REQUIRE
(
sink
->
msg_counter
()
<
messages
);
spdlog
::
drop_all
();
}
TEST_CASE
(
"flush"
,
"[async]"
)
...
...
@@ -73,11 +73,27 @@ TEST_CASE("flush", "[async]")
logger
->
flush
();
}
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
250
));
//
std::this_thread::sleep_for(std::chrono::milliseconds(250));
REQUIRE
(
test_sink
->
msg_counter
()
==
messages
);
REQUIRE
(
test_sink
->
flush_counter
()
==
1
);
}
TEST_CASE
(
"async periodic flush"
,
"[async]"
)
{
using
namespace
spdlog
;
auto
logger
=
spdlog
::
create_async
<
sinks
::
test_sink_mt
>
(
"as"
);
auto
test_sink
=
std
::
static_pointer_cast
<
sinks
::
test_sink_mt
>
(
logger
->
sinks
()[
0
]);
spdlog
::
flush_every
(
std
::
chrono
::
seconds
(
1
));
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
1100
));
REQUIRE
(
test_sink
->
flush_counter
()
==
1
);
spdlog
::
flush_every
(
std
::
chrono
::
seconds
(
0
));
spdlog
::
drop_all
();
}
TEST_CASE
(
"tp->wait_empty() "
,
"[async]"
)
{
using
namespace
spdlog
;
...
...
tests/test_misc.cpp
View file @
a96b4d75
#include "includes.h"
#include "test_sink.h"
template
<
class
T
>
std
::
string
log_info
(
const
T
&
what
,
spdlog
::
level
::
level_enum
logger_level
=
spdlog
::
level
::
info
)
...
...
@@ -75,3 +76,19 @@ TEST_CASE("to_level_enum", "[convert_to_level_enum]")
REQUIRE
(
spdlog
::
level
::
from_str
(
"off"
)
==
spdlog
::
level
::
off
);
REQUIRE
(
spdlog
::
level
::
from_str
(
"null"
)
==
spdlog
::
level
::
off
);
}
TEST_CASE
(
"periodic flush"
,
"[periodic_flush]"
)
{
using
namespace
spdlog
;
auto
logger
=
spdlog
::
create
<
sinks
::
test_sink_mt
>
(
"periodic_flush"
);
auto
test_sink
=
std
::
static_pointer_cast
<
sinks
::
test_sink_mt
>
(
logger
->
sinks
()[
0
]);
spdlog
::
flush_every
(
std
::
chrono
::
seconds
(
1
));
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
1100
));
REQUIRE
(
test_sink
->
flush_counter
()
==
1
);
spdlog
::
flush_every
(
std
::
chrono
::
seconds
(
0
));
spdlog
::
drop_all
();
}
tests/tests.vcxproj
View file @
a96b4d75
...
...
@@ -110,7 +110,7 @@
</ItemDefinitionGroup>
<ItemDefinitionGroup
Condition=
"'$(Configuration)|$(Platform)'=='Release|x64'"
>
<ClCompile>
<WarningLevel>
Level
4
</WarningLevel>
<WarningLevel>
Level
3
</WarningLevel>
<Optimization>
MaxSpeed
</Optimization>
<FunctionLevelLinking>
true
</FunctionLevelLinking>
<IntrinsicFunctions>
true
</IntrinsicFunctions>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment