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
8494590f
Commit
8494590f
authored
Mar 22, 2014
by
gabime
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
astyle+dos2unix
parent
6a83c344
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
950 additions
and
949 deletions
+950
-949
astyle.sh
astyle.sh
+2
-1
example.cpp
example/example.cpp
+4
-4
common_types.h
include/c11log/common_types.h
+29
-29
blocking_queue.h
include/c11log/details/blocking_queue.h
+125
-125
factory.h
include/c11log/details/factory.h
+61
-61
fast_buf.h
include/c11log/details/fast_buf.h
+11
-11
fast_oss.h
include/c11log/details/fast_oss.h
+106
-106
line_logger.h
include/c11log/details/line_logger.h
+75
-75
os.h
include/c11log/details/os.h
+63
-63
formatter.h
include/c11log/formatter.h
+97
-97
logger.h
include/c11log/logger.h
+163
-163
async_sink.h
include/c11log/sinks/async_sink.h
+116
-116
base_sink.h
include/c11log/sinks/base_sink.h
+51
-51
console_sinks.h
include/c11log/sinks/console_sinks.h
+47
-47
file_sinks.h
include/c11log/sinks/file_sinks.h
+0
-0
No files found.
astyle.sh
View file @
8494590f
#!/bin/bash
find
.
-name
"*
\.
h"
-o
-name
"*
\.
cpp"
|xargs astyle
-A1
find
.
-name
"*
\.
h"
-o
-name
"*
\.
cpp"
|xargs dos2unix
find
.
-name
"*
\.
h"
-o
-name
"*
\.
cpp"
|xargs astyle
-n
-A1
example/example.cpp
View file @
8494590f
...
...
@@ -32,12 +32,12 @@ int main(int argc, char* argv[])
logger
my_logger
(
"my_logger"
,
{
null_sink
});
std
::
string
s
(
100
,
'0'
);
const
unsigned
int
howmany
=
5000000
;
std
::
string
s
(
100
,
'0'
);
const
unsigned
int
howmany
=
5000000
;
auto
start
=
system_clock
::
now
();
for
(
unsigned
int
i
=
0
;
i
<
howmany
;
i
++
)
my_logger
.
info
()
<<
s
;
//my_logger.info() << "Hello logger " << i;;
my_logger
.
info
()
<<
s
;
//my_logger.info() << "Hello logger " << i;;
//async->shutdown(seconds(3));
auto
delta
=
system_clock
::
now
()
-
start
;
...
...
include/c11log/common_types.h
View file @
8494590f
#pragma once
#include <chrono>
namespace
c11log
{
typedef
std
::
chrono
::
system_clock
log_clock
;
typedef
std
::
pair
<
const
char
*
,
std
::
size_t
>
bufpair_t
;
namespace
level
{
typedef
enum
{
DEBUG
,
INFO
,
WARNING
,
ERROR
,
FATAL
,
NONE
=
99
}
level_enum
;
static
const
char
*
level_names
[]
{
"debug"
,
"info"
,
"warning"
,
"error"
,
"fatal"
};
inline
const
char
*
to_str
(
c11log
::
level
::
level_enum
l
)
{
return
level_names
[
l
];
}
}
}
#pragma once
#include <chrono>
namespace
c11log
{
typedef
std
::
chrono
::
system_clock
log_clock
;
typedef
std
::
pair
<
const
char
*
,
std
::
size_t
>
bufpair_t
;
namespace
level
{
typedef
enum
{
DEBUG
,
INFO
,
WARNING
,
ERROR
,
FATAL
,
NONE
=
99
}
level_enum
;
static
const
char
*
level_names
[]
{
"debug"
,
"info"
,
"warning"
,
"error"
,
"fatal"
};
inline
const
char
*
to_str
(
c11log
::
level
::
level_enum
l
)
{
return
level_names
[
l
];
}
}
}
include/c11log/details/blocking_queue.h
View file @
8494590f
#pragma once
// blocking_queue:
// A blocking multi-consumer/multi-producer thread safe queue.
// Has max capacity and supports timeout on push or pop operations.
#include <chrono>
#include <memory>
#include <queue>
#include <mutex>
#include <condition_variable>
namespace
c11log
{
namespace
details
{
template
<
typename
T
>
class
blocking_queue
{
public
:
using
queue_t
=
std
::
queue
<
T
>
;
using
size_type
=
typename
queue_t
::
size_type
;
using
clock
=
std
::
chrono
::
system_clock
;
explicit
blocking_queue
(
size_type
max_size
)
:
_max_size
(
max_size
),
_q
(),
_mutex
()
{
}
blocking_queue
(
const
blocking_queue
&
)
=
delete
;
blocking_queue
&
operator
=
(
const
blocking_queue
&
)
=
delete
;
~
blocking_queue
()
=
default
;
size_type
size
()
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
_mutex
);
return
_q
.
size
();
}
// Push copy of item into the back of the queue.
// If the queue is full, block the calling thread util there is room or timeout have passed.
// Return: false on timeout, true on successful push.
template
<
typename
Duration_Rep
,
typename
Duration_Period
,
typename
TT
>
bool
push
(
TT
&&
item
,
const
std
::
chrono
::
duration
<
Duration_Rep
,
Duration_Period
>&
timeout
)
{
std
::
unique_lock
<
std
::
mutex
>
ul
(
_mutex
);
if
(
_q
.
size
()
>=
_max_size
)
{
if
(
!
_item_popped_cond
.
wait_until
(
ul
,
clock
::
now
()
+
timeout
,
[
this
]()
{
return
this
->
_q
.
size
()
<
this
->
_max_size
;
}))
return
false
;
}
_q
.
push
(
std
::
forward
<
TT
>
(
item
));
if
(
_q
.
size
()
<=
1
)
{
ul
.
unlock
();
//So the notified thread will have better chance to accuire the lock immediatly..
_item_pushed_cond
.
notify_one
();
}
return
true
;
}
// Push copy of item into the back of the queue.
// If the queue is full, block the calling thread until there is room.
template
<
typename
TT
>
void
push
(
TT
&&
item
)
{
while
(
!
push
(
std
::
forward
<
TT
>
(
item
),
std
::
chrono
::
hours
(
1
)));
}
// Pop a copy of the front item in the queue into the given item ref.
// If the queue is empty, block the calling thread util there is item to pop or timeout have passed.
// Return: false on timeout , true on successful pop/
template
<
class
Duration_Rep
,
class
Duration_Period
>
bool
pop
(
T
&
item
,
const
std
::
chrono
::
duration
<
Duration_Rep
,
Duration_Period
>&
timeout
)
{
std
::
unique_lock
<
std
::
mutex
>
ul
(
_mutex
);
if
(
_q
.
empty
())
{
if
(
!
_item_pushed_cond
.
wait_until
(
ul
,
clock
::
now
()
+
timeout
,
[
this
]()
{
return
!
this
->
_q
.
empty
();
}))
return
false
;
}
item
=
std
::
move
(
_q
.
front
());
_q
.
pop
();
if
(
_q
.
size
()
>=
_max_size
-
1
)
{
ul
.
unlock
();
//So the notified thread will have better chance to accuire the lock immediatly..
_item_popped_cond
.
notify_one
();
}
return
true
;
}
// Pop a copy of the front item in the queue into the given item ref.
// If the queue is empty, block the calling thread util there is item to pop.
void
pop
(
T
&
item
)
{
while
(
!
pop
(
item
,
std
::
chrono
::
hours
(
1
)));
}
// Clear the queue
void
clear
()
{
{
std
::
unique_lock
<
std
::
mutex
>
ul
(
_mutex
);
queue_t
().
swap
(
_q
);
}
_item_popped_cond
.
notify_all
();
}
private
:
size_type
_max_size
;
std
::
queue
<
T
>
_q
;
std
::
mutex
_mutex
;
std
::
condition_variable
_item_pushed_cond
;
std
::
condition_variable
_item_popped_cond
;
};
}
}
#pragma once
// blocking_queue:
// A blocking multi-consumer/multi-producer thread safe queue.
// Has max capacity and supports timeout on push or pop operations.
#include <chrono>
#include <memory>
#include <queue>
#include <mutex>
#include <condition_variable>
namespace
c11log
{
namespace
details
{
template
<
typename
T
>
class
blocking_queue
{
public
:
using
queue_t
=
std
::
queue
<
T
>
;
using
size_type
=
typename
queue_t
::
size_type
;
using
clock
=
std
::
chrono
::
system_clock
;
explicit
blocking_queue
(
size_type
max_size
)
:
_max_size
(
max_size
),
_q
(),
_mutex
()
{
}
blocking_queue
(
const
blocking_queue
&
)
=
delete
;
blocking_queue
&
operator
=
(
const
blocking_queue
&
)
=
delete
;
~
blocking_queue
()
=
default
;
size_type
size
()
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
_mutex
);
return
_q
.
size
();
}
// Push copy of item into the back of the queue.
// If the queue is full, block the calling thread util there is room or timeout have passed.
// Return: false on timeout, true on successful push.
template
<
typename
Duration_Rep
,
typename
Duration_Period
,
typename
TT
>
bool
push
(
TT
&&
item
,
const
std
::
chrono
::
duration
<
Duration_Rep
,
Duration_Period
>&
timeout
)
{
std
::
unique_lock
<
std
::
mutex
>
ul
(
_mutex
);
if
(
_q
.
size
()
>=
_max_size
)
{
if
(
!
_item_popped_cond
.
wait_until
(
ul
,
clock
::
now
()
+
timeout
,
[
this
]()
{
return
this
->
_q
.
size
()
<
this
->
_max_size
;
}))
return
false
;
}
_q
.
push
(
std
::
forward
<
TT
>
(
item
));
if
(
_q
.
size
()
<=
1
)
{
ul
.
unlock
();
//So the notified thread will have better chance to accuire the lock immediatly..
_item_pushed_cond
.
notify_one
();
}
return
true
;
}
// Push copy of item into the back of the queue.
// If the queue is full, block the calling thread until there is room.
template
<
typename
TT
>
void
push
(
TT
&&
item
)
{
while
(
!
push
(
std
::
forward
<
TT
>
(
item
),
std
::
chrono
::
hours
(
1
)));
}
// Pop a copy of the front item in the queue into the given item ref.
// If the queue is empty, block the calling thread util there is item to pop or timeout have passed.
// Return: false on timeout , true on successful pop/
template
<
class
Duration_Rep
,
class
Duration_Period
>
bool
pop
(
T
&
item
,
const
std
::
chrono
::
duration
<
Duration_Rep
,
Duration_Period
>&
timeout
)
{
std
::
unique_lock
<
std
::
mutex
>
ul
(
_mutex
);
if
(
_q
.
empty
())
{
if
(
!
_item_pushed_cond
.
wait_until
(
ul
,
clock
::
now
()
+
timeout
,
[
this
]()
{
return
!
this
->
_q
.
empty
();
}))
return
false
;
}
item
=
std
::
move
(
_q
.
front
());
_q
.
pop
();
if
(
_q
.
size
()
>=
_max_size
-
1
)
{
ul
.
unlock
();
//So the notified thread will have better chance to accuire the lock immediatly..
_item_popped_cond
.
notify_one
();
}
return
true
;
}
// Pop a copy of the front item in the queue into the given item ref.
// If the queue is empty, block the calling thread util there is item to pop.
void
pop
(
T
&
item
)
{
while
(
!
pop
(
item
,
std
::
chrono
::
hours
(
1
)));
}
// Clear the queue
void
clear
()
{
{
std
::
unique_lock
<
std
::
mutex
>
ul
(
_mutex
);
queue_t
().
swap
(
_q
);
}
_item_popped_cond
.
notify_all
();
}
private
:
size_type
_max_size
;
std
::
queue
<
T
>
_q
;
std
::
mutex
_mutex
;
std
::
condition_variable
_item_pushed_cond
;
std
::
condition_variable
_item_popped_cond
;
};
}
}
include/c11log/details/factory.h
View file @
8494590f
#pragma once
#include <unordered_map>
#include <string>
#include <memory>
#include <mutex>
namespace
c11log
{
class
logger
;
namespace
details
{
class
factory
{
public
:
using
logger_ptr
=
std
::
shared_ptr
<
c11log
::
logger
>
;
using
logger_map
=
std
::
unordered_map
<
std
::
string
,
logger_ptr
>
;
void
add_logger
(
const
std
::
string
&
name
,
logger_ptr
);
logger_ptr
get_logger
(
const
std
::
string
&
name
);
static
c11log
::
details
::
factory
&
instance
();
private
:
std
::
mutex
_loggers_mutex
;
logger_map
_loggers
;
};
}
}
inline
void
c11log
::
details
::
factory
::
add_logger
(
const
std
::
string
&
name
,
logger_ptr
logger_p
)
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
_loggers_mutex
);
_loggers
.
insert
(
logger_map
::
value_type
(
name
,
logger_p
));
}
inline
c11log
::
details
::
factory
::
logger_ptr
c11log
::
details
::
factory
::
get_logger
(
const
std
::
string
&
name
)
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
_loggers_mutex
);
auto
found
=
_loggers
.
find
(
name
);
if
(
found
!=
_loggers
.
end
())
return
found
->
second
;
else
return
logger_ptr
(
nullptr
);
/*
auto found = _loggers.find(name);
if (found == _loggers.end()) {
auto new_logger_ptr = std::make_shared<c11log::logger>(name);
_loggers.insert(std::make_pair(name, new_logger_ptr));
return new_logger_ptr;
} else {
return found->second;
}*/
}
inline
c11log
::
details
::
factory
&
c11log
::
details
::
factory
::
instance
()
{
static
c11log
::
details
::
factory
instance
;
return
instance
;
}
#pragma once
#include <unordered_map>
#include <string>
#include <memory>
#include <mutex>
namespace
c11log
{
class
logger
;
namespace
details
{
class
factory
{
public
:
using
logger_ptr
=
std
::
shared_ptr
<
c11log
::
logger
>
;
using
logger_map
=
std
::
unordered_map
<
std
::
string
,
logger_ptr
>
;
void
add_logger
(
const
std
::
string
&
name
,
logger_ptr
);
logger_ptr
get_logger
(
const
std
::
string
&
name
);
static
c11log
::
details
::
factory
&
instance
();
private
:
std
::
mutex
_loggers_mutex
;
logger_map
_loggers
;
};
}
}
inline
void
c11log
::
details
::
factory
::
add_logger
(
const
std
::
string
&
name
,
logger_ptr
logger_p
)
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
_loggers_mutex
);
_loggers
.
insert
(
logger_map
::
value_type
(
name
,
logger_p
));
}
inline
c11log
::
details
::
factory
::
logger_ptr
c11log
::
details
::
factory
::
get_logger
(
const
std
::
string
&
name
)
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
_loggers_mutex
);
auto
found
=
_loggers
.
find
(
name
);
if
(
found
!=
_loggers
.
end
())
return
found
->
second
;
else
return
logger_ptr
(
nullptr
);
/*
auto found = _loggers.find(name);
if (found == _loggers.end()) {
auto new_logger_ptr = std::make_shared<c11log::logger>(name);
_loggers.insert(std::make_pair(name, new_logger_ptr));
return new_logger_ptr;
} else {
return found->second;
}*/
}
inline
c11log
::
details
::
factory
&
c11log
::
details
::
factory
::
instance
()
{
static
c11log
::
details
::
factory
instance
;
return
instance
;
}
include/c11log/details/fast_buf.h
View file @
8494590f
...
...
@@ -21,10 +21,10 @@ public:
fast_buf
()
:
_stack_size
(
0
)
{}
~
fast_buf
()
{};
fast_buf
(
const
bufpair_t
&
buf_to_copy
)
:
fast_buf
()
{
append
(
buf_to_copy
);
}
fast_buf
(
const
bufpair_t
&
buf_to_copy
)
:
fast_buf
()
{
append
(
buf_to_copy
);
}
fast_buf
(
const
fast_buf
&
other
)
{
...
...
@@ -46,7 +46,7 @@ public:
}
fast_buf
&
operator
=
(
const
fast_buf
&
other
)
=
delete
;
fast_buf
&
operator
=
(
fast_buf
&&
other
)
=
delete
;
fast_buf
&
operator
=
(
fast_buf
&&
other
)
=
delete
;
void
append
(
const
char
*
buf
,
std
::
size_t
size
)
{
...
...
@@ -66,7 +66,7 @@ public:
//Not enough stack space. Copy all to _v
else
{
_v
.
reserve
(
_stack_size
+
size
);
_v
.
reserve
(
_stack_size
+
size
);
if
(
_stack_size
)
_v
.
insert
(
_v
.
end
(),
_stack_buf
.
begin
(),
_stack_buf
.
begin
()
+
_stack_size
);
_v
.
insert
(
_v
.
end
(),
buf
,
buf
+
size
);
...
...
@@ -74,10 +74,10 @@ public:
}
}
void
append
(
const
bufpair_t
&
buf
)
{
append
(
buf
.
first
,
buf
.
second
);
}
void
append
(
const
bufpair_t
&
buf
)
{
append
(
buf
.
first
,
buf
.
second
);
}
void
clear
()
{
...
...
@@ -96,7 +96,7 @@ public:
private
:
std
::
vector
<
char
>
_v
;
std
::
array
<
char
,
STACK_SIZE
>
_stack_buf
;
std
::
size_t
_stack_size
;
std
::
size_t
_stack_size
;
};
}
...
...
include/c11log/details/fast_oss.h
View file @
8494590f
#pragma once
// Faster than ostringstream--returns its string by ref
#include "c11log/details/fast_buf.h"
namespace
c11log
{
namespace
details
{
class
str_devicebuf
:
public
std
::
streambuf
{
public
:
str_devicebuf
()
=
default
;
~
str_devicebuf
()
=
default
;
str_devicebuf
(
const
str_devicebuf
&
other
)
=
delete
;
str_devicebuf
(
str_devicebuf
&&
other
)
=
delete
;
str_devicebuf
&
operator
=
(
const
str_devicebuf
&
)
=
delete
;
str_devicebuf
&
operator
=
(
str_devicebuf
&&
)
=
delete
;
/*
const std::string& str_ref() const
{
return _str;
}
*/
bufpair_t
buf
()
{
return
_fastbuf
.
get
();
}
void
reset_str
()
{
//_str.clear();
_fastbuf
.
clear
();
}
protected
:
int
sync
()
override
{
return
0
;
}
// copy the give buffer into the accumulated string.
// reserve initially 128 bytes which should be enough for common log lines
std
::
streamsize
xsputn
(
const
char_type
*
s
,
std
::
streamsize
count
)
override
{
/*
if(_str.capacity() < k_initial_reserve)
{
_str.reserve(k_initial_reserve);
}
_str.append(s, static_cast<unsigned int>(count));
*/
_fastbuf
.
append
(
s
,
static_cast
<
unsigned
int
>
(
count
));
return
count
;
}
int_type
overflow
(
int_type
ch
)
override
{
bool
not_eofile
=
traits_type
::
not_eof
(
ch
);
if
(
not_eofile
)
{
char
c
=
traits_type
::
to_char_type
(
ch
);
xsputn
(
&
c
,
1
);
}
return
not_eofile
;
}
private
:
//std::string _str;
fast_buf
<
192
>
_fastbuf
;
};
class
fast_oss
:
public
std
::
ostream
{
public
:
fast_oss
()
:
std
::
ostream
(
&
_dev
)
{}
~
fast_oss
()
=
default
;
fast_oss
(
const
fast_oss
&
other
)
=
delete
;
fast_oss
(
fast_oss
&&
other
)
=
delete
;
fast_oss
&
operator
=
(
const
fast_oss
&
other
)
=
delete
;
/*
const std::string& str_ref() const
{
return _dev.str_ref();
}
*/
bufpair_t
buf
()
{
return
_dev
.
buf
();
}
void
reset_str
()
{
_dev
.
reset_str
();
}
private
:
str_devicebuf
_dev
;
};
}
}
#pragma once
// Faster than ostringstream--returns its string by ref
#include "c11log/details/fast_buf.h"
namespace
c11log
{
namespace
details
{
class
str_devicebuf
:
public
std
::
streambuf
{
public
:
str_devicebuf
()
=
default
;
~
str_devicebuf
()
=
default
;
str_devicebuf
(
const
str_devicebuf
&
other
)
=
delete
;
str_devicebuf
(
str_devicebuf
&&
other
)
=
delete
;
str_devicebuf
&
operator
=
(
const
str_devicebuf
&
)
=
delete
;
str_devicebuf
&
operator
=
(
str_devicebuf
&&
)
=
delete
;
/*
const std::string& str_ref() const
{
return _str;
}
*/
bufpair_t
buf
()
{
return
_fastbuf
.
get
();
}
void
reset_str
()
{
//_str.clear();
_fastbuf
.
clear
();
}
protected
:
int
sync
()
override
{
return
0
;
}
// copy the give buffer into the accumulated string.
// reserve initially 128 bytes which should be enough for common log lines
std
::
streamsize
xsputn
(
const
char_type
*
s
,
std
::
streamsize
count
)
override
{
/*
if(_str.capacity() < k_initial_reserve)
{
_str.reserve(k_initial_reserve);
}
_str.append(s, static_cast<unsigned int>(count));
*/
_fastbuf
.
append
(
s
,
static_cast
<
unsigned
int
>
(
count
));
return
count
;
}
int_type
overflow
(
int_type
ch
)
override
{
bool
not_eofile
=
traits_type
::
not_eof
(
ch
);
if
(
not_eofile
)
{
char
c
=
traits_type
::
to_char_type
(
ch
);
xsputn
(
&
c
,
1
);
}
return
not_eofile
;
}
private
:
//std::string _str;
fast_buf
<
192
>
_fastbuf
;
};
class
fast_oss
:
public
std
::
ostream
{
public
:
fast_oss
()
:
std
::
ostream
(
&
_dev
)
{}
~
fast_oss
()
=
default
;
fast_oss
(
const
fast_oss
&
other
)
=
delete
;
fast_oss
(
fast_oss
&&
other
)
=
delete
;
fast_oss
&
operator
=
(
const
fast_oss
&
other
)
=
delete
;
/*
const std::string& str_ref() const
{
return _dev.str_ref();
}
*/
bufpair_t
buf
()
{
return
_dev
.
buf
();
}
void
reset_str
()
{
_dev
.
reset_str
();
}
private
:
str_devicebuf
_dev
;
};
}
}
include/c11log/details/line_logger.h
View file @
8494590f
#pragma once
#include "../common_types.h"
#include "../logger.h"
#include "fast_oss.h"
// line logger class. should be used by the logger as an rvalue only.
// aggregates logging string until the end of the line and then calls the logger upon destruction
namespace
c11log
{
//class logger;
namespace
details
{
class
line_logger
{
public
:
line_logger
(
logger
*
callback_logger
,
level
::
level_enum
msg_level
,
bool
enabled
)
:
_callback_logger
(
callback_logger
),
_oss
(),
_level
(
msg_level
),
_enabled
(
enabled
)
{
if
(
enabled
)
{
callback_logger
->
_formatter
->
format_header
(
callback_logger
->
_logger_name
,
msg_level
,
log_clock
::
now
(),
_oss
);
}
}
// No copy intended. Only move
line_logger
(
const
line_logger
&
other
)
=
delete
;
line_logger
&
operator
=
(
const
line_logger
&
)
=
delete
;
line_logger
&
operator
=
(
line_logger
&&
)
=
delete
;
line_logger
(
line_logger
&&
other
)
:
_callback_logger
(
other
.
_callback_logger
),
// The move ctor should only be called on start of logging line,
// where no logging happened yet for this line so no need to copy the string from the other
_oss
(),
_level
(
other
.
_level
)
{};
~
line_logger
()
{
if
(
_enabled
)
{
_oss
<<
os
::
eol
();
_callback_logger
->
_log_it
(
_oss
.
buf
(),
_level
);
}
}
template
<
typename
T
>
line_logger
&&
operator
<<
(
const
T
&
msg
)
{
if
(
_enabled
)
_oss
<<
msg
;
return
std
::
move
(
*
this
);
}
private
:
logger
*
_callback_logger
;
details
::
fast_oss
_oss
;
level
::
level_enum
_level
;
bool
_enabled
;
};
}
//Namespace details
}
// Namespace c11log
#pragma once
#include "../common_types.h"
#include "../logger.h"
#include "fast_oss.h"
// line logger class. should be used by the logger as an rvalue only.
// aggregates logging string until the end of the line and then calls the logger upon destruction
namespace
c11log
{
//class logger;
namespace
details
{
class
line_logger
{
public
:
line_logger
(
logger
*
callback_logger
,
level
::
level_enum
msg_level
,
bool
enabled
)
:
_callback_logger
(
callback_logger
),
_oss
(),
_level
(
msg_level
),
_enabled
(
enabled
)
{
if
(
enabled
)
{
callback_logger
->
_formatter
->
format_header
(
callback_logger
->
_logger_name
,
msg_level
,
log_clock
::
now
(),
_oss
);
}
}
// No copy intended. Only move
line_logger
(
const
line_logger
&
other
)
=
delete
;
line_logger
&
operator
=
(
const
line_logger
&
)
=
delete
;
line_logger
&
operator
=
(
line_logger
&&
)
=
delete
;
line_logger
(
line_logger
&&
other
)
:
_callback_logger
(
other
.
_callback_logger
),
// The move ctor should only be called on start of logging line,
// where no logging happened yet for this line so no need to copy the string from the other
_oss
(),
_level
(
other
.
_level
)
{};
~
line_logger
()
{
if
(
_enabled
)
{
_oss
<<
os
::
eol
();
_callback_logger
->
_log_it
(
_oss
.
buf
(),
_level
);
}
}
template
<
typename
T
>
line_logger
&&
operator
<<
(
const
T
&
msg
)
{
if
(
_enabled
)
_oss
<<
msg
;
return
std
::
move
(
*
this
);
}
private
:
logger
*
_callback_logger
;
details
::
fast_oss
_oss
;
level
::
level_enum
_level
;
bool
_enabled
;
};
}
//Namespace details
}
// Namespace c11log
include/c11log/details/os.h
View file @
8494590f
#pragma once
#include<string>
#include<cstdio>
#include<ctime>
namespace
c11log
{
namespace
details
{
namespace
os
{
inline
std
::
tm
localtime
(
const
std
::
time_t
&
time_tt
)
{
std
::
tm
tm
;
#ifdef _WIN32
localtime_s
(
&
tm
,
&
time_tt
);
#else
localtime_r
(
&
time_tt
,
&
tm
);
#endif
return
tm
;
}
inline
std
::
tm
localtime
()
{
std
::
time_t
now_t
=
time
(
0
);
return
localtime
(
now_t
);
}
inline
bool
operator
==
(
const
std
::
tm
&
tm1
,
const
std
::
tm
&
tm2
)
{
return
(
tm1
.
tm_sec
==
tm2
.
tm_sec
&&
tm1
.
tm_min
==
tm2
.
tm_min
&&
tm1
.
tm_hour
==
tm2
.
tm_hour
&&
tm1
.
tm_mday
==
tm2
.
tm_mday
&&
tm1
.
tm_mon
==
tm2
.
tm_mon
&&
tm1
.
tm_year
==
tm2
.
tm_year
&&
tm1
.
tm_isdst
==
tm2
.
tm_isdst
);
}
inline
bool
operator
!=
(
const
std
::
tm
&
tm1
,
const
std
::
tm
&
tm2
)
{
return
!
(
tm1
==
tm2
);
}
constexpr
inline
const
char
*
eol
()
{
#ifdef _WIN32
return
"
\r\n
"
;
#else
return
"
\n
"
;
#endif
}
}
//os
}
//details
}
//c11log
#pragma once
#include<string>
#include<cstdio>
#include<ctime>
namespace
c11log
{
namespace
details
{
namespace
os
{
inline
std
::
tm
localtime
(
const
std
::
time_t
&
time_tt
)
{
std
::
tm
tm
;
#ifdef _WIN32
localtime_s
(
&
tm
,
&
time_tt
);
#else
localtime_r
(
&
time_tt
,
&
tm
);
#endif
return
tm
;
}
inline
std
::
tm
localtime
()
{
std
::
time_t
now_t
=
time
(
0
);
return
localtime
(
now_t
);
}
inline
bool
operator
==
(
const
std
::
tm
&
tm1
,
const
std
::
tm
&
tm2
)
{
return
(
tm1
.
tm_sec
==
tm2
.
tm_sec
&&
tm1
.
tm_min
==
tm2
.
tm_min
&&
tm1
.
tm_hour
==
tm2
.
tm_hour
&&
tm1
.
tm_mday
==
tm2
.
tm_mday
&&
tm1
.
tm_mon
==
tm2
.
tm_mon
&&
tm1
.
tm_year
==
tm2
.
tm_year
&&
tm1
.
tm_isdst
==
tm2
.
tm_isdst
);
}
inline
bool
operator
!=
(
const
std
::
tm
&
tm1
,
const
std
::
tm
&
tm2
)
{
return
!
(
tm1
==
tm2
);
}
constexpr
inline
const
char
*
eol
()
{
#ifdef _WIN32
return
"
\r\n
"
;
#else
return
"
\n
"
;
#endif
}
}
//os
}
//details
}
//c11log
include/c11log/formatter.h
View file @
8494590f
#pragma once
#include <string>
#include <chrono>
#include <functional>
#include <sstream>
#include <iomanip>
#include <thread>
#include <cstdlib>
#include <cstring>
#include "common_types.h"
#include "details/os.h"
#include "details/fast_oss.h"
namespace
c11log
{
namespace
formatters
{
typedef
std
::
function
<
std
::
string
(
const
std
::
string
&
logger_name
,
const
std
::
string
&
,
level
::
level_enum
,
const
c11log
::
log_clock
::
time_point
&
)
>
format_fn
;
class
formatter
{
public
:
formatter
()
{}
virtual
~
formatter
()
{}
virtual
void
format_header
(
const
std
::
string
&
logger_name
,
level
::
level_enum
level
,
const
log_clock
::
time_point
&
tp
,
std
::
ostream
&
dest
)
=
0
;
};
class
default_formatter
:
public
formatter
{
public
:
// Format: [2013-12-29 01:04:42.900] [logger_name:Info] Message body
void
format_header
(
const
std
::
string
&
logger_name
,
level
::
level_enum
level
,
const
log_clock
::
time_point
&
tp
,
std
::
ostream
&
dest
)
override
{
_format_time
(
tp
,
dest
);
if
(
!
logger_name
.
empty
())
dest
<<
" ["
<<
logger_name
<<
':'
<<
c11log
::
level
::
to_str
(
level
)
<<
"] "
;
else
dest
<<
" ["
<<
c11log
::
level
::
to_str
(
level
)
<<
"] "
;
}
private
:
void
_format_time
(
const
log_clock
::
time_point
&
tp
,
std
::
ostream
&
dest
);
};
}
//namespace formatter
}
//namespace c11log
// Format datetime like this: [2014-03-14 17:15:22]
inline
void
c11log
::
formatters
::
default_formatter
::
_format_time
(
const
log_clock
::
time_point
&
tp
,
std
::
ostream
&
dest
)
{
using
namespace
c11log
::
details
::
os
;
using
namespace
std
::
chrono
;
#ifdef _WIN32 //VS2013 doesn't support yet thread_local keyword
__declspec
(
thread
)
static
char
s_cache_str
[
64
];
__declspec
(
thread
)
static
size_t
s_cache_size
;
__declspec
(
thread
)
static
std
::
time_t
s_cache_time_t
=
0
;
#else
thread_local
static
char
s_cache_str
[
64
];
thread_local
static
size_t
s_cache_size
;
thread_local
static
std
::
time_t
s_cache_time_t
=
0
;
#endif
//Cache every second
std
::
time_t
tp_time_t
=
log_clock
::
to_time_t
(
tp
);
if
(
tp_time_t
!=
s_cache_time_t
)
{
auto
tm_now
=
details
::
os
::
localtime
(
tp_time_t
);
details
::
fast_oss
time_oss
;
time_oss
.
fill
(
'0'
);
time_oss
<<
'['
<<
tm_now
.
tm_year
+
1900
<<
'-'
;
time_oss
.
width
(
2
);
time_oss
<<
tm_now
.
tm_mon
+
1
<<
'-'
;
time_oss
.
width
(
2
);
time_oss
<<
tm_now
.
tm_mday
<<
' '
;
time_oss
.
width
(
2
);
time_oss
<<
tm_now
.
tm_hour
<<
':'
;
time_oss
.
width
(
2
);
time_oss
<<
tm_now
.
tm_min
<<
':'
;
time_oss
.
width
(
2
);
time_oss
<<
tm_now
.
tm_sec
<<
']'
;
//Cache the resulted string and its size
s_cache_time_t
=
tp_time_t
;
//const std::string &s = time_oss.str_ref();
bufpair_t
buf
=
time_oss
.
buf
();
std
::
memcpy
(
s_cache_str
,
buf
.
first
,
buf
.
second
);
s_cache_size
=
buf
.
second
;
}
dest
.
write
(
s_cache_str
,
s_cache_size
);
}
#pragma once
#include <string>
#include <chrono>
#include <functional>
#include <sstream>
#include <iomanip>
#include <thread>
#include <cstdlib>
#include <cstring>
#include "common_types.h"
#include "details/os.h"
#include "details/fast_oss.h"
namespace
c11log
{
namespace
formatters
{
typedef
std
::
function
<
std
::
string
(
const
std
::
string
&
logger_name
,
const
std
::
string
&
,
level
::
level_enum
,
const
c11log
::
log_clock
::
time_point
&
)
>
format_fn
;
class
formatter
{
public
:
formatter
()
{}
virtual
~
formatter
()
{}
virtual
void
format_header
(
const
std
::
string
&
logger_name
,
level
::
level_enum
level
,
const
log_clock
::
time_point
&
tp
,
std
::
ostream
&
dest
)
=
0
;
};
class
default_formatter
:
public
formatter
{
public
:
// Format: [2013-12-29 01:04:42.900] [logger_name:Info] Message body
void
format_header
(
const
std
::
string
&
logger_name
,
level
::
level_enum
level
,
const
log_clock
::
time_point
&
tp
,
std
::
ostream
&
dest
)
override
{
_format_time
(
tp
,
dest
);
if
(
!
logger_name
.
empty
())
dest
<<
" ["
<<
logger_name
<<
':'
<<
c11log
::
level
::
to_str
(
level
)
<<
"] "
;
else
dest
<<
" ["
<<
c11log
::
level
::
to_str
(
level
)
<<
"] "
;
}
private
:
void
_format_time
(
const
log_clock
::
time_point
&
tp
,
std
::
ostream
&
dest
);
};
}
//namespace formatter
}
//namespace c11log
// Format datetime like this: [2014-03-14 17:15:22]
inline
void
c11log
::
formatters
::
default_formatter
::
_format_time
(
const
log_clock
::
time_point
&
tp
,
std
::
ostream
&
dest
)
{
using
namespace
c11log
::
details
::
os
;
using
namespace
std
::
chrono
;
#ifdef _WIN32 //VS2013 doesn't support yet thread_local keyword
__declspec
(
thread
)
static
char
s_cache_str
[
64
];
__declspec
(
thread
)
static
size_t
s_cache_size
;
__declspec
(
thread
)
static
std
::
time_t
s_cache_time_t
=
0
;
#else
thread_local
static
char
s_cache_str
[
64
];
thread_local
static
size_t
s_cache_size
;
thread_local
static
std
::
time_t
s_cache_time_t
=
0
;
#endif
//Cache every second
std
::
time_t
tp_time_t
=
log_clock
::
to_time_t
(
tp
);
if
(
tp_time_t
!=
s_cache_time_t
)
{
auto
tm_now
=
details
::
os
::
localtime
(
tp_time_t
);
details
::
fast_oss
time_oss
;
time_oss
.
fill
(
'0'
);
time_oss
<<
'['
<<
tm_now
.
tm_year
+
1900
<<
'-'
;
time_oss
.
width
(
2
);
time_oss
<<
tm_now
.
tm_mon
+
1
<<
'-'
;
time_oss
.
width
(
2
);
time_oss
<<
tm_now
.
tm_mday
<<
' '
;
time_oss
.
width
(
2
);
time_oss
<<
tm_now
.
tm_hour
<<
':'
;
time_oss
.
width
(
2
);
time_oss
<<
tm_now
.
tm_min
<<
':'
;
time_oss
.
width
(
2
);
time_oss
<<
tm_now
.
tm_sec
<<
']'
;
//Cache the resulted string and its size
s_cache_time_t
=
tp_time_t
;
//const std::string &s = time_oss.str_ref();
bufpair_t
buf
=
time_oss
.
buf
();
std
::
memcpy
(
s_cache_str
,
buf
.
first
,
buf
.
second
);
s_cache_size
=
buf
.
second
;
}
dest
.
write
(
s_cache_str
,
s_cache_size
);
}
include/c11log/logger.h
View file @
8494590f
#pragma once
// Thread safe logger
// Has log level and vector sinks which do the actual logging
#include<vector>
#include<memory>
#include<mutex>
#include<atomic>
#include <algorithm>
#include "common_types.h"
#include "sinks/base_sink.h"
#include "details/factory.h"
#include "c11log/details/log_msg.h"
//Thread safe, fast logger.
//All initialization is done in ctor only, so we get away lot of locking
namespace
c11log
{
namespace
details
{
class
line_logger
;
template
<
std
::
size_t
>
class
fast_buf
;
}
class
logger
{
public
:
using
sink_ptr
=
std
::
shared_ptr
<
sinks
::
base_sink
>
;
using
formatter_ptr
=
std
::
shared_ptr
<
c11log
::
formatters
::
formatter
>
;
using
sinks_vector_t
=
std
::
vector
<
sink_ptr
>
;
using
sinks_init_list
=
std
::
initializer_list
<
sink_ptr
>
;
logger
(
const
std
::
string
&
name
,
formatter_ptr
,
sinks_init_list
);
logger
(
const
std
::
string
&
name
,
sinks_init_list
);
logger
(
sinks_init_list
sinks_list
);
~
logger
()
=
default
;
//Non copybale in anyway
logger
(
const
logger
&
)
=
delete
;
logger
(
logger
&&
)
=
delete
;
logger
&
operator
=
(
const
logger
&
)
=
delete
;
logger
&
operator
=
(
logger
&&
)
=
delete
;
void
set_level
(
c11log
::
level
::
level_enum
);
c11log
::
level
::
level_enum
get_level
()
const
;
const
std
::
string
&
get_name
()
const
;
bool
should_log
(
c11log
::
level
::
level_enum
)
const
;
details
::
line_logger
log
(
level
::
level_enum
);
details
::
line_logger
debug
();
details
::
line_logger
info
();
details
::
line_logger
warn
();
details
::
line_logger
error
();
details
::
line_logger
fatal
();
private
:
friend
details
::
line_logger
;
std
::
string
_logger_name
=
""
;
formatter_ptr
_formatter
;
sinks_vector_t
_sinks
;
std
::
atomic_int
_atomic_level
;
void
_log_it
(
const
bufpair_t
&
buf
,
const
level
::
level_enum
level
);
};
logger
&
get_logger
(
const
std
::
string
&
name
);
}
//
// Logger inline implementation
//
#include "details/line_logger.h"
#include "details/fast_buf.h"
inline
c11log
::
logger
::
logger
(
const
std
::
string
&
name
,
formatter_ptr
f
,
sinks_init_list
sinks_list
)
:
_logger_name
(
name
),
_formatter
(
f
),
_sinks
(
sinks_list
)
{
//Seems that vs2013 doesnt support atomic member initialization in ctor, so its done here
_atomic_level
=
level
::
INFO
;
}
inline
c11log
::
logger
::
logger
(
const
std
::
string
&
name
,
sinks_init_list
sinks_list
)
:
logger
(
name
,
std
::
make_shared
<
formatters
::
default_formatter
>
(),
sinks_list
)
{}
inline
c11log
::
logger
::
logger
(
sinks_init_list
sinks_list
)
:
logger
(
""
,
std
::
make_shared
<
formatters
::
default_formatter
>
(),
sinks_list
)
{}
inline
c11log
::
details
::
line_logger
c11log
::
logger
::
log
(
c11log
::
level
::
level_enum
msg_level
)
{
return
details
::
line_logger
(
this
,
msg_level
,
msg_level
>=
_atomic_level
);
}
inline
c11log
::
details
::
line_logger
c11log
::
logger
::
debug
()
{
return
log
(
c11log
::
level
::
DEBUG
);
}
inline
c11log
::
details
::
line_logger
c11log
::
logger
::
info
()
{
return
log
(
c11log
::
level
::
INFO
);
}
inline
c11log
::
details
::
line_logger
c11log
::
logger
::
warn
()
{
return
log
(
c11log
::
level
::
WARNING
);
}
inline
c11log
::
details
::
line_logger
c11log
::
logger
::
error
()
{
return
log
(
level
::
ERROR
);
}
inline
c11log
::
details
::
line_logger
c11log
::
logger
::
fatal
()
{
return
log
(
c11log
::
level
::
FATAL
);
}
inline
const
std
::
string
&
c11log
::
logger
::
get_name
()
const
{
return
_logger_name
;
}
inline
void
c11log
::
logger
::
set_level
(
c11log
::
level
::
level_enum
level
)
{
_atomic_level
.
store
(
level
);
}
inline
c11log
::
level
::
level_enum
c11log
::
logger
::
get_level
()
const
{
return
static_cast
<
c11log
::
level
::
level_enum
>
(
_atomic_level
.
load
());
}
inline
bool
c11log
::
logger
::
should_log
(
c11log
::
level
::
level_enum
level
)
const
{
return
level
>=
_atomic_level
.
load
();
}
inline
void
c11log
::
logger
::
_log_it
(
const
bufpair_t
&
buf
,
const
level
::
level_enum
level
)
{
for
(
auto
&
sink
:
_sinks
)
sink
->
log
(
buf
,
level
);
}
// Static factory function
inline
c11log
::
logger
&
c11log
::
get_logger
(
const
std
::
string
&
name
)
{
return
*
(
c11log
::
details
::
factory
::
instance
().
get_logger
(
name
));
}
#pragma once
// Thread safe logger
// Has log level and vector sinks which do the actual logging
#include<vector>
#include<memory>
#include<mutex>
#include<atomic>
#include <algorithm>
#include "common_types.h"
#include "sinks/base_sink.h"
#include "details/factory.h"
#include "c11log/details/log_msg.h"
//Thread safe, fast logger.
//All initialization is done in ctor only, so we get away lot of locking
namespace
c11log
{
namespace
details
{
class
line_logger
;
template
<
std
::
size_t
>
class
fast_buf
;
}
class
logger
{
public
:
using
sink_ptr
=
std
::
shared_ptr
<
sinks
::
base_sink
>
;
using
formatter_ptr
=
std
::
shared_ptr
<
c11log
::
formatters
::
formatter
>
;
using
sinks_vector_t
=
std
::
vector
<
sink_ptr
>
;
using
sinks_init_list
=
std
::
initializer_list
<
sink_ptr
>
;
logger
(
const
std
::
string
&
name
,
formatter_ptr
,
sinks_init_list
);
logger
(
const
std
::
string
&
name
,
sinks_init_list
);
logger
(
sinks_init_list
sinks_list
);
~
logger
()
=
default
;
//Non copybale in anyway
logger
(
const
logger
&
)
=
delete
;
logger
(
logger
&&
)
=
delete
;
logger
&
operator
=
(
const
logger
&
)
=
delete
;
logger
&
operator
=
(
logger
&&
)
=
delete
;
void
set_level
(
c11log
::
level
::
level_enum
);
c11log
::
level
::
level_enum
get_level
()
const
;
const
std
::
string
&
get_name
()
const
;
bool
should_log
(
c11log
::
level
::
level_enum
)
const
;
details
::
line_logger
log
(
level
::
level_enum
);
details
::
line_logger
debug
();
details
::
line_logger
info
();
details
::
line_logger
warn
();
details
::
line_logger
error
();
details
::
line_logger
fatal
();
private
:
friend
details
::
line_logger
;
std
::
string
_logger_name
=
""
;
formatter_ptr
_formatter
;
sinks_vector_t
_sinks
;
std
::
atomic_int
_atomic_level
;
void
_log_it
(
const
bufpair_t
&
buf
,
const
level
::
level_enum
level
);
};
logger
&
get_logger
(
const
std
::
string
&
name
);
}
//
// Logger inline implementation
//
#include "details/line_logger.h"
#include "details/fast_buf.h"
inline
c11log
::
logger
::
logger
(
const
std
::
string
&
name
,
formatter_ptr
f
,
sinks_init_list
sinks_list
)
:
_logger_name
(
name
),
_formatter
(
f
),
_sinks
(
sinks_list
)
{
//Seems that vs2013 doesnt support atomic member initialization in ctor, so its done here
_atomic_level
=
level
::
INFO
;
}
inline
c11log
::
logger
::
logger
(
const
std
::
string
&
name
,
sinks_init_list
sinks_list
)
:
logger
(
name
,
std
::
make_shared
<
formatters
::
default_formatter
>
(),
sinks_list
)
{}
inline
c11log
::
logger
::
logger
(
sinks_init_list
sinks_list
)
:
logger
(
""
,
std
::
make_shared
<
formatters
::
default_formatter
>
(),
sinks_list
)
{}
inline
c11log
::
details
::
line_logger
c11log
::
logger
::
log
(
c11log
::
level
::
level_enum
msg_level
)
{
return
details
::
line_logger
(
this
,
msg_level
,
msg_level
>=
_atomic_level
);
}
inline
c11log
::
details
::
line_logger
c11log
::
logger
::
debug
()
{
return
log
(
c11log
::
level
::
DEBUG
);
}
inline
c11log
::
details
::
line_logger
c11log
::
logger
::
info
()
{
return
log
(
c11log
::
level
::
INFO
);
}
inline
c11log
::
details
::
line_logger
c11log
::
logger
::
warn
()
{
return
log
(
c11log
::
level
::
WARNING
);
}
inline
c11log
::
details
::
line_logger
c11log
::
logger
::
error
()
{
return
log
(
level
::
ERROR
);
}
inline
c11log
::
details
::
line_logger
c11log
::
logger
::
fatal
()
{
return
log
(
c11log
::
level
::
FATAL
);
}
inline
const
std
::
string
&
c11log
::
logger
::
get_name
()
const
{
return
_logger_name
;
}
inline
void
c11log
::
logger
::
set_level
(
c11log
::
level
::
level_enum
level
)
{
_atomic_level
.
store
(
level
);
}
inline
c11log
::
level
::
level_enum
c11log
::
logger
::
get_level
()
const
{
return
static_cast
<
c11log
::
level
::
level_enum
>
(
_atomic_level
.
load
());
}
inline
bool
c11log
::
logger
::
should_log
(
c11log
::
level
::
level_enum
level
)
const
{
return
level
>=
_atomic_level
.
load
();
}
inline
void
c11log
::
logger
::
_log_it
(
const
bufpair_t
&
buf
,
const
level
::
level_enum
level
)
{
for
(
auto
&
sink
:
_sinks
)
sink
->
log
(
buf
,
level
);
}
// Static factory function
inline
c11log
::
logger
&
c11log
::
get_logger
(
const
std
::
string
&
name
)
{
return
*
(
c11log
::
details
::
factory
::
instance
().
get_logger
(
name
));
}
include/c11log/sinks/async_sink.h
View file @
8494590f
#pragma once
#include <thread>
#include <chrono>
#include <atomic>
#include "base_sink.h"
#include "../logger.h"
#include "../details/blocking_queue.h"
namespace
c11log
{
namespace
sinks
{
class
async_sink
:
public
base_sink
{
public
:
using
size_type
=
c11log
::
details
::
blocking_queue
<
std
::
string
>::
size_type
;
explicit
async_sink
(
const
size_type
max_queue_size
);
~
async_sink
();
void
add_sink
(
logger
::
sink_ptr
sink
);
void
remove_sink
(
logger
::
sink_ptr
sink_ptr
);
//Wait to remaining items (if any) in the queue to be written and shutdown
void
shutdown
(
const
std
::
chrono
::
seconds
&
timeout
);
protected
:
void
_sink_it
(
const
bufpair_t
&
msg
)
override
;
void
_thread_loop
();
private
:
c11log
::
logger
::
sinks_vector_t
_sinks
;
std
::
atomic
<
bool
>
_active
;
c11log
::
details
::
blocking_queue
<
std
::
string
>
_q
;
std
::
thread
_back_thread
;
//Clear all remaining messages(if any), stop the _back_thread and join it
void
_shutdown
();
};
}
}
///////////////////////////////////////////////////////////////////////////////
// async_sink class implementation
///////////////////////////////////////////////////////////////////////////////
inline
c11log
::
sinks
::
async_sink
::
async_sink
(
const
std
::
size_t
max_queue_size
)
:
_sinks
(),
_active
(
true
),
_q
(
max_queue_size
),
_back_thread
(
&
async_sink
::
_thread_loop
,
this
)
{}
inline
c11log
::
sinks
::
async_sink
::~
async_sink
()
{
_shutdown
();
}
inline
void
c11log
::
sinks
::
async_sink
::
_sink_it
(
const
bufpair_t
&
msg
)
{
std
::
string
s
{
msg
.
first
,
msg
.
first
+
msg
.
second
};
_q
.
push
(
s
);
}
inline
void
c11log
::
sinks
::
async_sink
::
_thread_loop
()
{
static
std
::
chrono
::
seconds
pop_timeout
{
1
};
std
::
string
msg
;
while
(
_active
)
{
if
(
_q
.
pop
(
msg
,
pop_timeout
))
{
bufpair_t
buf
(
msg
.
data
(),
msg
.
size
());
for
(
auto
&
sink
:
_sinks
)
{
sink
->
log
(
buf
,
static_cast
<
level
::
level_enum
>
(
_level
.
load
()));
if
(
!
_active
)
return
;
}
}
}
}
inline
void
c11log
::
sinks
::
async_sink
::
add_sink
(
logger
::
sink_ptr
sink
)
{
_sinks
.
push_back
(
sink
);
}
inline
void
c11log
::
sinks
::
async_sink
::
remove_sink
(
logger
::
sink_ptr
sink_ptr
)
{
_sinks
.
erase
(
std
::
remove
(
_sinks
.
begin
(),
_sinks
.
end
(),
sink_ptr
),
_sinks
.
end
());
}
inline
void
c11log
::
sinks
::
async_sink
::
shutdown
(
const
std
::
chrono
::
seconds
&
timeout
)
{
auto
until
=
std
::
chrono
::
system_clock
::
now
()
+
timeout
;
while
(
_q
.
size
()
>
0
&&
std
::
chrono
::
system_clock
::
now
()
<
until
)
{
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
200
));
}
_shutdown
();
}
inline
void
c11log
::
sinks
::
async_sink
::
_shutdown
()
{
if
(
_active
)
{
_active
=
false
;
if
(
_back_thread
.
joinable
())
_back_thread
.
join
();
}
}
#pragma once
#include <thread>
#include <chrono>
#include <atomic>
#include "base_sink.h"
#include "../logger.h"
#include "../details/blocking_queue.h"
namespace
c11log
{
namespace
sinks
{
class
async_sink
:
public
base_sink
{
public
:
using
size_type
=
c11log
::
details
::
blocking_queue
<
std
::
string
>::
size_type
;
explicit
async_sink
(
const
size_type
max_queue_size
);
~
async_sink
();
void
add_sink
(
logger
::
sink_ptr
sink
);
void
remove_sink
(
logger
::
sink_ptr
sink_ptr
);
//Wait to remaining items (if any) in the queue to be written and shutdown
void
shutdown
(
const
std
::
chrono
::
seconds
&
timeout
);
protected
:
void
_sink_it
(
const
bufpair_t
&
msg
)
override
;
void
_thread_loop
();
private
:
c11log
::
logger
::
sinks_vector_t
_sinks
;
std
::
atomic
<
bool
>
_active
;
c11log
::
details
::
blocking_queue
<
std
::
string
>
_q
;
std
::
thread
_back_thread
;
//Clear all remaining messages(if any), stop the _back_thread and join it
void
_shutdown
();
};
}
}
///////////////////////////////////////////////////////////////////////////////
// async_sink class implementation
///////////////////////////////////////////////////////////////////////////////
inline
c11log
::
sinks
::
async_sink
::
async_sink
(
const
std
::
size_t
max_queue_size
)
:
_sinks
(),
_active
(
true
),
_q
(
max_queue_size
),
_back_thread
(
&
async_sink
::
_thread_loop
,
this
)
{}
inline
c11log
::
sinks
::
async_sink
::~
async_sink
()
{
_shutdown
();
}
inline
void
c11log
::
sinks
::
async_sink
::
_sink_it
(
const
bufpair_t
&
msg
)
{
std
::
string
s
{
msg
.
first
,
msg
.
first
+
msg
.
second
};
_q
.
push
(
s
);
}
inline
void
c11log
::
sinks
::
async_sink
::
_thread_loop
()
{
static
std
::
chrono
::
seconds
pop_timeout
{
1
};
std
::
string
msg
;
while
(
_active
)
{
if
(
_q
.
pop
(
msg
,
pop_timeout
))
{
bufpair_t
buf
(
msg
.
data
(),
msg
.
size
());
for
(
auto
&
sink
:
_sinks
)
{
sink
->
log
(
buf
,
static_cast
<
level
::
level_enum
>
(
_level
.
load
()));
if
(
!
_active
)
return
;
}
}
}
}
inline
void
c11log
::
sinks
::
async_sink
::
add_sink
(
logger
::
sink_ptr
sink
)
{
_sinks
.
push_back
(
sink
);
}
inline
void
c11log
::
sinks
::
async_sink
::
remove_sink
(
logger
::
sink_ptr
sink_ptr
)
{
_sinks
.
erase
(
std
::
remove
(
_sinks
.
begin
(),
_sinks
.
end
(),
sink_ptr
),
_sinks
.
end
());
}
inline
void
c11log
::
sinks
::
async_sink
::
shutdown
(
const
std
::
chrono
::
seconds
&
timeout
)
{
auto
until
=
std
::
chrono
::
system_clock
::
now
()
+
timeout
;
while
(
_q
.
size
()
>
0
&&
std
::
chrono
::
system_clock
::
now
()
<
until
)
{
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
200
));
}
_shutdown
();
}
inline
void
c11log
::
sinks
::
async_sink
::
_shutdown
()
{
if
(
_active
)
{
_active
=
false
;
if
(
_back_thread
.
joinable
())
_back_thread
.
join
();
}
}
include/c11log/sinks/base_sink.h
View file @
8494590f
#pragma once
#include<string>
#include<atomic>
#include "../formatter.h"
#include "../common_types.h"
namespace
c11log
{
namespace
sinks
{
class
base_sink
{
public
:
base_sink
()
=
default
;
base_sink
(
level
::
level_enum
l
)
:
_level
(
l
)
{
};
virtual
~
base_sink
()
=
default
;
base_sink
(
const
base_sink
&
)
=
delete
;
base_sink
&
operator
=
(
const
base_sink
&
)
=
delete
;
void
log
(
const
bufpair_t
&
msg
,
level
::
level_enum
level
)
{
if
(
level
>=
_level
)
{
_sink_it
(
msg
);
}
};
void
set_level
(
level
::
level_enum
level
)
{
_level
=
level
;
}
protected
:
virtual
void
_sink_it
(
const
bufpair_t
&
msg
)
=
0
;
std
::
atomic
<
int
>
_level
{
level
::
INFO
};
};
class
null_sink
:
public
base_sink
{
protected
:
void
_sink_it
(
const
bufpair_t
&
)
override
{
}
};
}
}
#pragma once
#include<string>
#include<atomic>
#include "../formatter.h"
#include "../common_types.h"
namespace
c11log
{
namespace
sinks
{
class
base_sink
{
public
:
base_sink
()
=
default
;
base_sink
(
level
::
level_enum
l
)
:
_level
(
l
)
{
};
virtual
~
base_sink
()
=
default
;
base_sink
(
const
base_sink
&
)
=
delete
;
base_sink
&
operator
=
(
const
base_sink
&
)
=
delete
;
void
log
(
const
bufpair_t
&
msg
,
level
::
level_enum
level
)
{
if
(
level
>=
_level
)
{
_sink_it
(
msg
);
}
};
void
set_level
(
level
::
level_enum
level
)
{
_level
=
level
;
}
protected
:
virtual
void
_sink_it
(
const
bufpair_t
&
msg
)
=
0
;
std
::
atomic
<
int
>
_level
{
level
::
INFO
};
};
class
null_sink
:
public
base_sink
{
protected
:
void
_sink_it
(
const
bufpair_t
&
)
override
{
}
};
}
}
include/c11log/sinks/console_sinks.h
View file @
8494590f
#pragma once
#include <iostream>
#include <mutex>
#include <memory>
#include "base_sink.h"
namespace
c11log
{
namespace
sinks
{
class
console_sink
:
public
base_sink
{
public
:
explicit
console_sink
(
std
::
ostream
&
os
)
:
_ostream
(
os
)
{}
console_sink
(
const
console_sink
&
)
=
delete
;
console_sink
&
operator
=
(
const
console_sink
&
)
=
delete
;
virtual
~
console_sink
()
=
default
;
protected
:
virtual
void
_sink_it
(
const
bufpair_t
&
msg
)
override
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
_mutex
);
_ostream
.
write
(
msg
.
first
,
msg
.
second
);
}
std
::
ostream
&
_ostream
;
std
::
mutex
_mutex
;
};
inline
std
::
shared_ptr
<
console_sink
>&
stdout_sink
()
{
static
auto
inst
=
std
::
make_shared
<
console_sink
>
(
std
::
cout
);
return
inst
;
}
inline
std
::
shared_ptr
<
console_sink
>&
stderr_sink
()
{
static
auto
inst
=
std
::
make_shared
<
console_sink
>
(
std
::
cerr
);
return
inst
;
}
}
}
#pragma once
#include <iostream>
#include <mutex>
#include <memory>
#include "base_sink.h"
namespace
c11log
{
namespace
sinks
{
class
console_sink
:
public
base_sink
{
public
:
explicit
console_sink
(
std
::
ostream
&
os
)
:
_ostream
(
os
)
{}
console_sink
(
const
console_sink
&
)
=
delete
;
console_sink
&
operator
=
(
const
console_sink
&
)
=
delete
;
virtual
~
console_sink
()
=
default
;
protected
:
virtual
void
_sink_it
(
const
bufpair_t
&
msg
)
override
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
_mutex
);
_ostream
.
write
(
msg
.
first
,
msg
.
second
);
}
std
::
ostream
&
_ostream
;
std
::
mutex
_mutex
;
};
inline
std
::
shared_ptr
<
console_sink
>&
stdout_sink
()
{
static
auto
inst
=
std
::
make_shared
<
console_sink
>
(
std
::
cout
);
return
inst
;
}
inline
std
::
shared_ptr
<
console_sink
>&
stderr_sink
()
{
static
auto
inst
=
std
::
make_shared
<
console_sink
>
(
std
::
cerr
);
return
inst
;
}
}
}
include/c11log/sinks/file_sinks.h
View file @
8494590f
This diff is collapsed.
Click to expand it.
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