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
314afa7d
Commit
314afa7d
authored
May 19, 2018
by
gabime
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
removed debug printf
parent
b1a58cd3
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
71 additions
and
105 deletions
+71
-105
async_log_helper.h
include/spdlog/details/async_log_helper.h
+71
-105
No files found.
include/spdlog/details/async_log_helper.h
View file @
314afa7d
...
...
@@ -14,11 +14,12 @@
#include "../common.h"
#include "../details/log_msg.h"
#include "../details/mpmc_b
ounded
_q.h"
#include "../details/mpmc_b
locking
_q.h"
#include "../details/os.h"
#include "../formatter.h"
#include "../sinks/sink.h"
#include<iostream>
#include <chrono>
#include <exception>
#include <functional>
...
...
@@ -27,12 +28,13 @@
#include <thread>
#include <utility>
#include <vector>
#include <condition_variable>
namespace
spdlog
{
namespace
details
{
namespace
details
{
class
async_log_helper
{
class
async_log_helper
{
// Async msg to move to/from the queue
// Movable only. should never be copied
enum
class
async_msg_type
...
...
@@ -115,9 +117,9 @@ class async_log_helper
}
};
public
:
public
:
using
item_type
=
async_msg
;
using
q_type
=
details
::
mpmc_bounded_queue
<
item_type
>
;
using
q_type
=
details
::
mpmc_bounded_queue
<
item_type
>
;
using
clock
=
std
::
chrono
::
steady_clock
;
...
...
@@ -136,11 +138,11 @@ public:
void
set_formatter
(
formatter_ptr
msg_formatter
);
void
flush
(
bool
wait_for_q
);
void
flush
(
);
void
set_error_handler
(
spdlog
::
log_err_handler
err_handler
);
private
:
private
:
formatter_ptr
_formatter
;
std
::
vector
<
std
::
shared_ptr
<
sinks
::
sink
>>
_sinks
;
...
...
@@ -149,9 +151,7 @@ private:
log_err_handler
_err_handler
;
bool
_flush_requested
;
bool
_terminate_requested
;
std
::
chrono
::
time_point
<
log_clock
>
_last_flush
;
// overflow policy
const
async_overflow_policy
_overflow_policy
;
...
...
@@ -165,27 +165,29 @@ private:
// worker thread teardown callback
const
std
::
function
<
void
()
>
_worker_teardown_cb
;
std
::
mutex
null_mutex_
;
//null_mutex null_mutex_;
std
::
condition_variable_any
not_empty_cv_
;
std
::
condition_variable_any
not_full_cv_
;
// worker thread
std
::
thread
_worker_thread
;
void
push_msg
(
async_msg
&&
new_msg
);
void
enqueue_msg
(
async_msg
&&
new_msg
,
async_overflow_policy
policy
);
// worker thread main loop
void
worker_loop
();
// pop next message from the queue and process it. will set the last_pop to the pop time
// dequeue next message from the queue and process it.
// return false if termination of the queue is required
bool
process_next_msg
(
log_clock
::
time_point
&
last_pop
,
log_clock
::
time_point
&
last_flush
);
bool
process_next_msg
(
);
void
handle_flush_interval
(
log_clock
::
time_point
&
now
,
log_clock
::
time_point
&
last_flush
);
void
handle_flush_interval
(
);
// sleep,yield or return immediately using the time passed since last message as a hint
static
void
sleep_or_yield
(
const
spdlog
::
log_clock
::
time_point
&
now
,
const
log_clock
::
time_point
&
last_op_time
);
void
flush_sinks
();
// wait until the queue is empty
void
wait_empty_q
();
};
}
// namespace details
};
}
// namespace details
}
// namespace spdlog
///////////////////////////////////////////////////////////////////////////////
...
...
@@ -198,8 +200,7 @@ inline spdlog::details::async_log_helper::async_log_helper(formatter_ptr formatt
,
_sinks
(
std
::
move
(
sinks
))
,
_q
(
queue_size
)
,
_err_handler
(
std
::
move
(
err_handler
))
,
_flush_requested
(
false
)
,
_terminate_requested
(
false
)
,
_last_flush
(
os
::
now
())
,
_overflow_policy
(
overflow_policy
)
,
_worker_warmup_cb
(
std
::
move
(
worker_warmup_cb
))
,
_flush_interval_ms
(
flush_interval_ms
)
...
...
@@ -214,7 +215,7 @@ inline spdlog::details::async_log_helper::~async_log_helper()
{
try
{
push_msg
(
async_msg
(
async_msg_type
::
terminate
)
);
enqueue_msg
(
async_msg
(
async_msg_type
::
terminate
),
async_overflow_policy
::
block_retry
);
_worker_thread
.
join
();
}
catch
(...)
// don't crash in destructor
...
...
@@ -225,31 +226,28 @@ inline spdlog::details::async_log_helper::~async_log_helper()
// Try to push and block until succeeded (if the policy is not to discard when the queue is full)
inline
void
spdlog
::
details
::
async_log_helper
::
log
(
const
details
::
log_msg
&
msg
)
{
push_msg
(
async_msg
(
msg
));
enqueue_msg
(
async_msg
(
msg
),
_overflow_policy
);
}
inline
void
spdlog
::
details
::
async_log_helper
::
push_msg
(
details
::
async_log_helper
::
async_msg
&&
new_msg
)
inline
void
spdlog
::
details
::
async_log_helper
::
enqueue_msg
(
details
::
async_log_helper
::
async_msg
&&
new_msg
,
async_overflow_policy
policy
)
{
if
(
!
_q
.
enqueue
(
std
::
move
(
new_msg
))
&&
_overflow_policy
!=
async_overflow_policy
::
discard_log_msg
)
// block until succeeded pushing to the queue
if
(
policy
==
async_overflow_policy
::
block_retry
)
{
auto
last_op_time
=
details
::
os
::
now
(
);
auto
now
=
last_op_time
;
do
_q
.
enqueue
(
std
::
move
(
new_msg
)
);
}
else
{
now
=
details
::
os
::
now
();
sleep_or_yield
(
now
,
last_op_time
);
}
while
(
!
_q
.
enqueue
(
std
::
move
(
new_msg
)));
_q
.
enqueue_nowait
(
std
::
move
(
new_msg
));
}
}
// optionally wait for the queue be empty and request flush from the sinks
inline
void
spdlog
::
details
::
async_log_helper
::
flush
(
bool
wait_for_q
)
inline
void
spdlog
::
details
::
async_log_helper
::
flush
()
{
push_msg
(
async_msg
(
async_msg_type
::
flush
));
if
(
wait_for_q
)
{
wait_empty_q
();
// return when queue is empty
}
enqueue_msg
(
async_msg
(
async_msg_type
::
flush
),
_overflow_policy
);
}
inline
void
spdlog
::
details
::
async_log_helper
::
worker_loop
()
...
...
@@ -258,14 +256,12 @@ inline void spdlog::details::async_log_helper::worker_loop()
{
_worker_warmup_cb
();
}
auto
last_pop
=
details
::
os
::
now
();
auto
last_flush
=
last_pop
;
auto
active
=
true
;
while
(
active
)
{
try
{
active
=
process_next_msg
(
last_pop
,
last_flush
);
active
=
process_next_msg
();
}
catch
(
const
std
::
exception
&
ex
)
{
...
...
@@ -284,23 +280,27 @@ inline void spdlog::details::async_log_helper::worker_loop()
// process next message in the queue
// return true if this thread should still be active (while no terminate msg was received)
inline
bool
spdlog
::
details
::
async_log_helper
::
process_next_msg
(
log_clock
::
time_point
&
last_pop
,
log_clock
::
time_point
&
last_flush
)
inline
bool
spdlog
::
details
::
async_log_helper
::
process_next_msg
()
{
async_msg
incoming_async_msg
;
if
(
_q
.
dequeue
(
incoming_async_msg
)
)
bool
dequeued
=
_q
.
dequeue_for
(
incoming_async_msg
,
std
::
chrono
::
milliseconds
(
1000
));
if
(
!
dequeued
)
{
last_pop
=
details
::
os
::
now
();
handle_flush_interval
();
return
true
;
}
switch
(
incoming_async_msg
.
msg_type
)
{
case
async_msg_type
:
:
flush
:
_flush_requested
=
true
;
break
;
flush_sinks
();
return
true
;
case
async_msg_type
:
:
terminate
:
_flush_requested
=
true
;
_terminate_requested
=
tru
e
;
break
;
//flush_sinks()
;
return
fals
e
;
default
:
log_msg
incoming_log_msg
;
...
...
@@ -313,81 +313,47 @@ inline bool spdlog::details::async_log_helper::process_next_msg(log_clock::time_
s
->
log
(
incoming_log_msg
);
}
}
}
return
true
;
}
assert
(
false
);
return
true
;
// should not be reached
// Handle empty queue..
// This is the only place where the queue can terminate or flush to avoid losing messages already in the queue
auto
now
=
details
::
os
::
now
();
handle_flush_interval
(
now
,
last_flush
);
sleep_or_yield
(
now
,
last_pop
);
return
!
_terminate_requested
;
}
// flush all sinks if _flush_interval_ms has expired
inline
void
spdlog
::
details
::
async_log_helper
::
handle_flush_interval
(
log_clock
::
time_point
&
now
,
log_clock
::
time_point
&
last_flush
)
// flush all sinks if _flush_interval_ms has expired
. only called if queue is empty
inline
void
spdlog
::
details
::
async_log_helper
::
handle_flush_interval
()
{
auto
should_flush
=
_flush_requested
||
(
_flush_interval_ms
!=
std
::
chrono
::
milliseconds
::
zero
()
&&
now
-
last_flush
>=
_flush_interval_ms
);
if
(
should_flush
)
if
(
_flush_interval_ms
==
std
::
chrono
::
milliseconds
::
zero
())
{
for
(
auto
&
s
:
_sinks
)
{
s
->
flush
();
return
;
}
now
=
last_flush
=
details
::
os
::
now
();
_flush_requested
=
false
;
auto
delta
=
details
::
os
::
now
()
-
_last_flush
;;
if
(
delta
>=
_flush_interval_ms
)
{
flush_sinks
();
}
}
inline
void
spdlog
::
details
::
async_log_helper
::
set_formatter
(
formatter_ptr
msg_formatter
)
{
_formatter
=
std
::
move
(
msg_formatter
);
}
// spin, yield or sleep. use the time passed since last message as a hint
inline
void
spdlog
::
details
::
async_log_helper
::
sleep_or_yield
(
const
spdlog
::
log_clock
::
time_point
&
now
,
const
spdlog
::
log_clock
::
time_point
&
last_op_time
)
{
using
std
::
chrono
::
microseconds
;
using
std
::
chrono
::
milliseconds
;
auto
time_since_op
=
now
-
last_op_time
;
// spin upto 50 micros
if
(
time_since_op
<=
microseconds
(
50
))
{
return
;
}
// yield upto 150 micros
if
(
time_since_op
<=
microseconds
(
100
))
{
return
std
::
this_thread
::
yield
();
}
// sleep for 20 ms upto 200 ms
if
(
time_since_op
<=
milliseconds
(
200
))
{
return
details
::
os
::
sleep_for_millis
(
20
);
}
// sleep for 500 ms
return
details
::
os
::
sleep_for_millis
(
500
);
inline
void
spdlog
::
details
::
async_log_helper
::
set_error_handler
(
spdlog
::
log_err_handler
err_handler
)
{
_err_handler
=
std
::
move
(
err_handler
);
}
// wait for the queue to be empty
inline
void
spdlog
::
details
::
async_log_helper
::
wait_empty_q
()
// flush all sinks if _flush_interval_ms has expired. only called if queue is empty
inline
void
spdlog
::
details
::
async_log_helper
::
flush_sinks
()
{
auto
last_op
=
details
::
os
::
now
();
while
(
!
_q
.
is_empty
())
for
(
auto
&
s
:
_sinks
)
{
sleep_or_yield
(
details
::
os
::
now
(),
last_op
);
s
->
flush
(
);
}
_last_flush
=
os
::
now
();
}
inline
void
spdlog
::
details
::
async_log_helper
::
set_error_handler
(
spdlog
::
log_err_handler
err_handler
)
{
_err_handler
=
std
::
move
(
err_handler
);
}
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