Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
S
spdlog
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
spdlog
Commits
0d263598
Commit
0d263598
authored
Apr 20, 2016
by
gabime
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
astyle
parent
0f889969
Changes
39
Hide whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
8951 additions
and
8951 deletions
+8951
-8951
bench/spdlog-async.cpp
bench/spdlog-async.cpp
+62
-62
bench/zf_log-bench-mt.cpp
bench/zf_log-bench-mt.cpp
+56
-56
bench/zf_log-bench.cpp
bench/zf_log-bench.cpp
+28
-28
example/example.cpp
example/example.cpp
+118
-118
include/spdlog/async_logger.h
include/spdlog/async_logger.h
+74
-74
include/spdlog/common.h
include/spdlog/common.h
+130
-130
include/spdlog/details/async_log_helper.h
include/spdlog/details/async_log_helper.h
+368
-368
include/spdlog/details/async_logger_impl.h
include/spdlog/details/async_logger_impl.h
+74
-74
include/spdlog/details/file_helper.h
include/spdlog/details/file_helper.h
+142
-142
include/spdlog/details/format.h
include/spdlog/details/format.h
+4500
-4500
include/spdlog/details/line_logger_fwd.h
include/spdlog/details/line_logger_fwd.h
+78
-78
include/spdlog/details/line_logger_impl.h
include/spdlog/details/line_logger_impl.h
+185
-185
include/spdlog/details/log_msg.h
include/spdlog/details/log_msg.h
+81
-81
include/spdlog/details/logger_impl.h
include/spdlog/details/logger_impl.h
+302
-302
include/spdlog/details/mpmc_bounded_q.h
include/spdlog/details/mpmc_bounded_q.h
+159
-159
include/spdlog/details/null_mutex.h
include/spdlog/details/null_mutex.h
+12
-12
include/spdlog/details/os.h
include/spdlog/details/os.h
+246
-246
include/spdlog/details/pattern_formatter_impl.h
include/spdlog/details/pattern_formatter_impl.h
+628
-628
include/spdlog/details/registry.h
include/spdlog/details/registry.h
+163
-163
include/spdlog/details/spdlog_impl.h
include/spdlog/details/spdlog_impl.h
+149
-149
include/spdlog/formatter.h
include/spdlog/formatter.h
+45
-45
include/spdlog/logger.h
include/spdlog/logger.h
+112
-112
include/spdlog/sinks/android_sink.h
include/spdlog/sinks/android_sink.h
+92
-92
include/spdlog/sinks/ansicolor_sink.h
include/spdlog/sinks/ansicolor_sink.h
+115
-115
include/spdlog/sinks/base_sink.h
include/spdlog/sinks/base_sink.h
+45
-45
include/spdlog/sinks/dist_sink.h
include/spdlog/sinks/dist_sink.h
+72
-72
include/spdlog/sinks/file_sinks.h
include/spdlog/sinks/file_sinks.h
+220
-220
include/spdlog/sinks/msvc_sink.h
include/spdlog/sinks/msvc_sink.h
+50
-50
include/spdlog/sinks/null_sink.h
include/spdlog/sinks/null_sink.h
+34
-34
include/spdlog/sinks/ostream_sink.h
include/spdlog/sinks/ostream_sink.h
+47
-47
include/spdlog/sinks/sink.h
include/spdlog/sinks/sink.h
+24
-24
include/spdlog/sinks/stdout_sinks.h
include/spdlog/sinks/stdout_sinks.h
+74
-74
include/spdlog/sinks/syslog_sink.h
include/spdlog/sinks/syslog_sink.h
+83
-83
include/spdlog/spdlog.h
include/spdlog/spdlog.h
+139
-139
tests/file_helper.cpp
tests/file_helper.cpp
+77
-77
tests/file_log.cpp
tests/file_log.cpp
+91
-91
tests/includes.h
tests/includes.h
+16
-16
tests/utils.cpp
tests/utils.cpp
+45
-45
tests/utils.h
tests/utils.h
+15
-15
No files found.
bench/spdlog-async.cpp
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include <thread>
#include <vector>
#include <atomic>
#include <iostream>
#include <chrono>
#include <cstdlib>
#include "spdlog/spdlog.h"
using
namespace
std
;
int
main
(
int
argc
,
char
*
argv
[])
{
using
namespace
std
::
chrono
;
using
clock
=
steady_clock
;
namespace
spd
=
spdlog
;
int
thread_count
=
10
;
if
(
argc
>
1
)
thread_count
=
::
atoi
(
argv
[
1
]);
int
howmany
=
1000000
;
spd
::
set_async_mode
(
1048576
);
auto
logger
=
spdlog
::
create
<
spd
::
sinks
::
simple_file_sink_mt
>
(
"file_logger"
,
"logs/spd-bench-async.txt"
,
false
);
logger
->
set_pattern
(
"[%Y-%b-%d %T.%e]: %v"
);
std
::
atomic
<
int
>
msg_counter
{
0
};
vector
<
thread
>
threads
;
auto
start
=
clock
::
now
();
for
(
int
t
=
0
;
t
<
thread_count
;
++
t
)
{
threads
.
push_back
(
std
::
thread
([
&
]()
{
while
(
true
)
{
int
counter
=
++
msg_counter
;
if
(
counter
>
howmany
)
break
;
logger
->
info
()
<<
"spdlog message #"
<<
counter
<<
": This is some text for your pleasure"
;
}
}));
}
for
(
auto
&
t
:
threads
)
{
t
.
join
();
};
duration
<
float
>
delta
=
clock
::
now
()
-
start
;
float
deltaf
=
delta
.
count
();
auto
rate
=
howmany
/
deltaf
;
cout
<<
"Total: "
<<
howmany
<<
std
::
endl
;
cout
<<
"Threads: "
<<
thread_count
<<
std
::
endl
;
std
::
cout
<<
"Delta = "
<<
deltaf
<<
" seconds"
<<
std
::
endl
;
std
::
cout
<<
"Rate = "
<<
rate
<<
"/sec"
<<
std
::
endl
;
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#include <thread>
#include <vector>
#include <atomic>
#include <iostream>
#include <chrono>
#include <cstdlib>
#include "spdlog/spdlog.h"
using
namespace
std
;
int
main
(
int
argc
,
char
*
argv
[])
{
using
namespace
std
::
chrono
;
using
clock
=
steady_clock
;
namespace
spd
=
spdlog
;
int
thread_count
=
10
;
if
(
argc
>
1
)
thread_count
=
::
atoi
(
argv
[
1
]);
int
howmany
=
1000000
;
spd
::
set_async_mode
(
1048576
);
auto
logger
=
spdlog
::
create
<
spd
::
sinks
::
simple_file_sink_mt
>
(
"file_logger"
,
"logs/spd-bench-async.txt"
,
false
);
logger
->
set_pattern
(
"[%Y-%b-%d %T.%e]: %v"
);
std
::
atomic
<
int
>
msg_counter
{
0
};
vector
<
thread
>
threads
;
auto
start
=
clock
::
now
();
for
(
int
t
=
0
;
t
<
thread_count
;
++
t
)
{
threads
.
push_back
(
std
::
thread
([
&
]()
{
while
(
true
)
{
int
counter
=
++
msg_counter
;
if
(
counter
>
howmany
)
break
;
logger
->
info
()
<<
"spdlog message #"
<<
counter
<<
": This is some text for your pleasure"
;
}
}));
}
for
(
auto
&
t
:
threads
)
{
t
.
join
();
};
duration
<
float
>
delta
=
clock
::
now
()
-
start
;
float
deltaf
=
delta
.
count
();
auto
rate
=
howmany
/
deltaf
;
cout
<<
"Total: "
<<
howmany
<<
std
::
endl
;
cout
<<
"Threads: "
<<
thread_count
<<
std
::
endl
;
std
::
cout
<<
"Delta = "
<<
deltaf
<<
" seconds"
<<
std
::
endl
;
std
::
cout
<<
"Rate = "
<<
rate
<<
"/sec"
<<
std
::
endl
;
}
bench/zf_log-bench-mt.cpp
View file @
0d263598
#include <thread>
#include <vector>
#include <atomic>
#include <cstdlib>
#include <unistd.h>
#include <fcntl.h>
#include <zf_log.c>
const
char
g_path
[]
=
"logs/zf_log.txt"
;
int
g_fd
;
static
void
output_callback
(
zf_log_message
*
msg
)
{
*
msg
->
p
=
'\n'
;
write
(
g_fd
,
msg
->
buf
,
msg
->
p
-
msg
->
buf
+
1
);
}
using
namespace
std
;
int
main
(
int
argc
,
char
*
argv
[])
{
g_fd
=
open
(
g_path
,
O_APPEND
|
O_CREAT
|
O_WRONLY
);
if
(
0
>
g_fd
)
{
ZF_LOGE_AUX
(
ZF_LOG_STDERR
,
"Failed to open log file: %s"
,
g_path
);
return
-
1
;
}
zf_log_set_output_callback
(
ZF_LOG_PUT_STD
,
output_callback
);
int
thread_count
=
10
;
if
(
argc
>
1
)
thread_count
=
std
::
atoi
(
argv
[
1
]);
int
howmany
=
1000000
;
std
::
atomic
<
int
>
msg_counter
{
0
};
vector
<
thread
>
threads
;
for
(
int
t
=
0
;
t
<
thread_count
;
++
t
)
{
threads
.
push_back
(
std
::
thread
([
&
]()
{
while
(
true
)
{
int
counter
=
++
msg_counter
;
if
(
counter
>
howmany
)
break
;
ZF_LOGI
(
"zf_log message #%i: This is some text for your pleasure"
,
counter
);
}
}));
}
for
(
auto
&
t
:
threads
)
{
t
.
join
();
};
close
(
g_fd
);
return
0
;
}
#include <thread>
#include <vector>
#include <atomic>
#include <cstdlib>
#include <unistd.h>
#include <fcntl.h>
#include <zf_log.c>
const
char
g_path
[]
=
"logs/zf_log.txt"
;
int
g_fd
;
static
void
output_callback
(
zf_log_message
*
msg
)
{
*
msg
->
p
=
'\n'
;
write
(
g_fd
,
msg
->
buf
,
msg
->
p
-
msg
->
buf
+
1
);
}
using
namespace
std
;
int
main
(
int
argc
,
char
*
argv
[])
{
g_fd
=
open
(
g_path
,
O_APPEND
|
O_CREAT
|
O_WRONLY
);
if
(
0
>
g_fd
)
{
ZF_LOGE_AUX
(
ZF_LOG_STDERR
,
"Failed to open log file: %s"
,
g_path
);
return
-
1
;
}
zf_log_set_output_callback
(
ZF_LOG_PUT_STD
,
output_callback
);
int
thread_count
=
10
;
if
(
argc
>
1
)
thread_count
=
std
::
atoi
(
argv
[
1
]);
int
howmany
=
1000000
;
std
::
atomic
<
int
>
msg_counter
{
0
};
vector
<
thread
>
threads
;
for
(
int
t
=
0
;
t
<
thread_count
;
++
t
)
{
threads
.
push_back
(
std
::
thread
([
&
]()
{
while
(
true
)
{
int
counter
=
++
msg_counter
;
if
(
counter
>
howmany
)
break
;
ZF_LOGI
(
"zf_log message #%i: This is some text for your pleasure"
,
counter
);
}
}));
}
for
(
auto
&
t
:
threads
)
{
t
.
join
();
};
close
(
g_fd
);
return
0
;
}
bench/zf_log-bench.cpp
View file @
0d263598
#include <stdio.h>
#include <zf_log.c>
const
char
g_path
[]
=
"logs/zf_log.txt"
;
static
FILE
*
g_f
;
static
void
output_callback
(
zf_log_message
*
msg
)
{
*
msg
->
p
=
'\n'
;
fwrite
(
msg
->
buf
,
msg
->
p
-
msg
->
buf
+
1
,
1
,
g_f
);
}
int
main
(
int
,
char
*
[])
{
g_f
=
fopen
(
g_path
,
"wb"
);
if
(
!
g_f
)
{
ZF_LOGE_AUX
(
ZF_LOG_STDERR
,
"Failed to open log file: %s"
,
g_path
);
return
-
1
;
}
zf_log_set_output_callback
(
ZF_LOG_PUT_STD
,
output_callback
);
const
int
howmany
=
1000000
;
for
(
int
i
=
0
;
i
<
howmany
;
++
i
)
ZF_LOGI
(
"zf_log message #%i: This is some text for your pleasure"
,
i
);
fclose
(
g_f
);
return
0
;
}
#include <stdio.h>
#include <zf_log.c>
const
char
g_path
[]
=
"logs/zf_log.txt"
;
static
FILE
*
g_f
;
static
void
output_callback
(
zf_log_message
*
msg
)
{
*
msg
->
p
=
'\n'
;
fwrite
(
msg
->
buf
,
msg
->
p
-
msg
->
buf
+
1
,
1
,
g_f
);
}
int
main
(
int
,
char
*
[])
{
g_f
=
fopen
(
g_path
,
"wb"
);
if
(
!
g_f
)
{
ZF_LOGE_AUX
(
ZF_LOG_STDERR
,
"Failed to open log file: %s"
,
g_path
);
return
-
1
;
}
zf_log_set_output_callback
(
ZF_LOG_PUT_STD
,
output_callback
);
const
int
howmany
=
1000000
;
for
(
int
i
=
0
;
i
<
howmany
;
++
i
)
ZF_LOGI
(
"zf_log message #%i: This is some text for your pleasure"
,
i
);
fclose
(
g_f
);
return
0
;
}
example/example.cpp
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
//
// spdlog usage example
//
#include "spdlog/spdlog.h"
#include <cstdlib> // EXIT_FAILURE
#include <iostream>
#include <memory>
void
async_example
();
void
syslog_example
();
namespace
spd
=
spdlog
;
int
main
(
int
,
char
*
[])
{
try
{
// Multithreaded color console
auto
console
=
spd
::
stdout_logger_mt
(
"console"
,
true
);
console
->
info
(
"Welcome to spdlog!"
);
console
->
info
(
"An info message example {}.."
,
1
);
console
->
info
()
<<
"Streams are supported too "
<<
1
;
// Formatting examples
console
->
info
(
"Easy padding in numbers like {:08d}"
,
12
);
console
->
info
(
"Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}"
,
42
);
console
->
info
(
"Support for floats {:03.2f}"
,
1.23456
);
console
->
info
(
"Positional args are {1} {0}.."
,
"too"
,
"supported"
);
console
->
info
(
"{:<30}"
,
"left aligned"
);
console
->
info
(
"{:>30}"
,
"right aligned"
);
console
->
info
(
"{:^30}"
,
"centered"
);
spd
::
get
(
"console"
)
->
info
(
"loggers can be retrieved from a global registry using the spdlog::get(logger_name) function"
);
// Runtime log levels
spd
::
set_level
(
spd
::
level
::
info
);
//Set global log level to info
console
->
debug
(
"This message shold not be displayed!"
);
console
->
set_level
(
spd
::
level
::
debug
);
// Set specific logger's log level
console
->
debug
(
"This message shold be displayed.."
);
// Create a file rotating logger with 5mb size max and 3 rotated files
auto
file_logger
=
spd
::
rotating_logger_mt
(
"file_logger"
,
"logs/mylogfile"
,
1048576
*
5
,
3
);
for
(
int
i
=
0
;
i
<
10
;
++
i
)
file_logger
->
info
(
"{} * {} equals {:>10}"
,
i
,
i
,
i
*
i
);
// Create a daily logger - a new file is created every day on 2:30am
auto
daily_logger
=
spd
::
daily_logger_mt
(
"daily_logger"
,
"logs/daily"
,
2
,
30
);
// Customize msg format for all messages
spd
::
set_pattern
(
"*** [%H:%M:%S %z] [thread %t] %v ***"
);
file_logger
->
info
(
"This is another message with custom format"
);
// Compile time debug or trace macros.
// Enabled #ifdef SPDLOG_DEBUG_ON or #ifdef SPDLOG_TRACE_ON
SPDLOG_TRACE
(
console
,
"Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}"
,
1
,
3.23
);
SPDLOG_DEBUG
(
console
,
"Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}"
,
1
,
3.23
);
// Asynchronous logging is very fast..
// Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
async_example
();
// syslog example. linux/osx only..
syslog_example
();
// Release and close all loggers
spdlog
::
drop_all
();
}
catch
(
const
spd
::
spdlog_ex
&
ex
)
{
std
::
cout
<<
"Log failed: "
<<
ex
.
what
()
<<
std
::
endl
;
return
EXIT_FAILURE
;
}
return
EXIT_SUCCESS
;
}
void
async_example
()
{
size_t
q_size
=
4096
;
//queue size must be power of 2
spdlog
::
set_async_mode
(
q_size
);
auto
async_file
=
spd
::
daily_logger_st
(
"async_file_logger"
,
"logs/async_log.txt"
);
for
(
int
i
=
0
;
i
<
100
;
++
i
)
async_file
->
info
(
"Async message #{}"
,
i
);
}
//syslog example (linux/osx only)
void
syslog_example
()
{
#if defined (__linux__) || defined(__APPLE__)
std
::
string
ident
=
"spdlog-example"
;
auto
syslog_logger
=
spd
::
syslog_logger
(
"syslog"
,
ident
,
LOG_PID
);
syslog_logger
->
warn
(
"This is warning that will end up in syslog. This is Linux only!"
);
#endif
}
// Example of user defined class with operator<<
class
some_class
{};
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
some_class
&
)
{
return
os
<<
"some_class"
;
}
void
custom_class_example
()
{
some_class
c
;
spdlog
::
get
(
"console"
)
->
info
(
"custom class with operator<<: {}.."
,
c
);
spdlog
::
get
(
"console"
)
->
info
()
<<
"custom class with operator<<: "
<<
c
<<
".."
;
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
//
// spdlog usage example
//
#include "spdlog/spdlog.h"
#include <cstdlib> // EXIT_FAILURE
#include <iostream>
#include <memory>
void
async_example
();
void
syslog_example
();
namespace
spd
=
spdlog
;
int
main
(
int
,
char
*
[])
{
try
{
// Multithreaded color console
auto
console
=
spd
::
stdout_logger_mt
(
"console"
,
true
);
console
->
info
(
"Welcome to spdlog!"
);
console
->
info
(
"An info message example {}.."
,
1
);
console
->
info
()
<<
"Streams are supported too "
<<
1
;
// Formatting examples
console
->
info
(
"Easy padding in numbers like {:08d}"
,
12
);
console
->
info
(
"Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}"
,
42
);
console
->
info
(
"Support for floats {:03.2f}"
,
1.23456
);
console
->
info
(
"Positional args are {1} {0}.."
,
"too"
,
"supported"
);
console
->
info
(
"{:<30}"
,
"left aligned"
);
console
->
info
(
"{:>30}"
,
"right aligned"
);
console
->
info
(
"{:^30}"
,
"centered"
);
spd
::
get
(
"console"
)
->
info
(
"loggers can be retrieved from a global registry using the spdlog::get(logger_name) function"
);
// Runtime log levels
spd
::
set_level
(
spd
::
level
::
info
);
//Set global log level to info
console
->
debug
(
"This message shold not be displayed!"
);
console
->
set_level
(
spd
::
level
::
debug
);
// Set specific logger's log level
console
->
debug
(
"This message shold be displayed.."
);
// Create a file rotating logger with 5mb size max and 3 rotated files
auto
file_logger
=
spd
::
rotating_logger_mt
(
"file_logger"
,
"logs/mylogfile"
,
1048576
*
5
,
3
);
for
(
int
i
=
0
;
i
<
10
;
++
i
)
file_logger
->
info
(
"{} * {} equals {:>10}"
,
i
,
i
,
i
*
i
);
// Create a daily logger - a new file is created every day on 2:30am
auto
daily_logger
=
spd
::
daily_logger_mt
(
"daily_logger"
,
"logs/daily"
,
2
,
30
);
// Customize msg format for all messages
spd
::
set_pattern
(
"*** [%H:%M:%S %z] [thread %t] %v ***"
);
file_logger
->
info
(
"This is another message with custom format"
);
// Compile time debug or trace macros.
// Enabled #ifdef SPDLOG_DEBUG_ON or #ifdef SPDLOG_TRACE_ON
SPDLOG_TRACE
(
console
,
"Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}"
,
1
,
3.23
);
SPDLOG_DEBUG
(
console
,
"Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}"
,
1
,
3.23
);
// Asynchronous logging is very fast..
// Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
async_example
();
// syslog example. linux/osx only..
syslog_example
();
// Release and close all loggers
spdlog
::
drop_all
();
}
catch
(
const
spd
::
spdlog_ex
&
ex
)
{
std
::
cout
<<
"Log failed: "
<<
ex
.
what
()
<<
std
::
endl
;
return
EXIT_FAILURE
;
}
return
EXIT_SUCCESS
;
}
void
async_example
()
{
size_t
q_size
=
4096
;
//queue size must be power of 2
spdlog
::
set_async_mode
(
q_size
);
auto
async_file
=
spd
::
daily_logger_st
(
"async_file_logger"
,
"logs/async_log.txt"
);
for
(
int
i
=
0
;
i
<
100
;
++
i
)
async_file
->
info
(
"Async message #{}"
,
i
);
}
//syslog example (linux/osx only)
void
syslog_example
()
{
#if defined (__linux__) || defined(__APPLE__)
std
::
string
ident
=
"spdlog-example"
;
auto
syslog_logger
=
spd
::
syslog_logger
(
"syslog"
,
ident
,
LOG_PID
);
syslog_logger
->
warn
(
"This is warning that will end up in syslog. This is Linux only!"
);
#endif
}
// Example of user defined class with operator<<
class
some_class
{};
std
::
ostream
&
operator
<<
(
std
::
ostream
&
os
,
const
some_class
&
)
{
return
os
<<
"some_class"
;
}
void
custom_class_example
()
{
some_class
c
;
spdlog
::
get
(
"console"
)
->
info
(
"custom class with operator<<: {}.."
,
c
);
spdlog
::
get
(
"console"
)
->
info
()
<<
"custom class with operator<<: "
<<
c
<<
".."
;
}
include/spdlog/async_logger.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Very fast asynchronous logger (millions of logs per second on an average desktop)
// Uses pre allocated lockfree queue for maximum throughput even under large number of threads.
// Creates a single back thread to pop messages from the queue and log them.
//
// Upon each log write the logger:
// 1. Checks if its log level is enough to log the message
// 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue)
// 3. will throw spdlog_ex upon log exceptions
// Upong destruction, logs all remaining messages in the queue before destructing..
#include <spdlog/common.h>
#include <spdlog/logger.h>
#include <chrono>
#include <functional>
#include <string>
#include <memory>
namespace
spdlog
{
namespace
details
{
class
async_log_helper
;
}
class
async_logger
:
public
logger
{
public:
template
<
class
It
>
async_logger
(
const
std
::
string
&
name
,
const
It
&
begin
,
const
It
&
end
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
=
async_overflow_policy
::
block_retry
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
=
nullptr
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
=
std
::
chrono
::
milliseconds
::
zero
());
async_logger
(
const
std
::
string
&
logger_name
,
sinks_init_list
sinks
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
=
async_overflow_policy
::
block_retry
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
=
nullptr
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
=
std
::
chrono
::
milliseconds
::
zero
());
async_logger
(
const
std
::
string
&
logger_name
,
sink_ptr
single_sink
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
=
async_overflow_policy
::
block_retry
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
=
nullptr
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
=
std
::
chrono
::
milliseconds
::
zero
());
void
flush
()
override
;
protected:
void
_log_msg
(
details
::
log_msg
&
msg
)
override
;
void
_set_formatter
(
spdlog
::
formatter_ptr
msg_formatter
)
override
;
void
_set_pattern
(
const
std
::
string
&
pattern
)
override
;
private:
std
::
unique_ptr
<
details
::
async_log_helper
>
_async_log_helper
;
};
}
#include <spdlog/details/async_logger_impl.h>
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Very fast asynchronous logger (millions of logs per second on an average desktop)
// Uses pre allocated lockfree queue for maximum throughput even under large number of threads.
// Creates a single back thread to pop messages from the queue and log them.
//
// Upon each log write the logger:
// 1. Checks if its log level is enough to log the message
// 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue)
// 3. will throw spdlog_ex upon log exceptions
// Upong destruction, logs all remaining messages in the queue before destructing..
#include <spdlog/common.h>
#include <spdlog/logger.h>
#include <chrono>
#include <functional>
#include <string>
#include <memory>
namespace
spdlog
{
namespace
details
{
class
async_log_helper
;
}
class
async_logger
:
public
logger
{
public:
template
<
class
It
>
async_logger
(
const
std
::
string
&
name
,
const
It
&
begin
,
const
It
&
end
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
=
async_overflow_policy
::
block_retry
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
=
nullptr
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
=
std
::
chrono
::
milliseconds
::
zero
());
async_logger
(
const
std
::
string
&
logger_name
,
sinks_init_list
sinks
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
=
async_overflow_policy
::
block_retry
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
=
nullptr
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
=
std
::
chrono
::
milliseconds
::
zero
());
async_logger
(
const
std
::
string
&
logger_name
,
sink_ptr
single_sink
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
=
async_overflow_policy
::
block_retry
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
=
nullptr
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
=
std
::
chrono
::
milliseconds
::
zero
());
void
flush
()
override
;
protected:
void
_log_msg
(
details
::
log_msg
&
msg
)
override
;
void
_set_formatter
(
spdlog
::
formatter_ptr
msg_formatter
)
override
;
void
_set_pattern
(
const
std
::
string
&
pattern
)
override
;
private:
std
::
unique_ptr
<
details
::
async_log_helper
>
_async_log_helper
;
};
}
#include <spdlog/details/async_logger_impl.h>
include/spdlog/common.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <string>
#include <initializer_list>
#include <chrono>
#include <memory>
#include <atomic>
#include <exception>
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#include <codecvt>
#include <locale>
#endif
#include <spdlog/details/null_mutex.h>
//visual studio does not support noexcept yet
#ifndef _MSC_VER
#define SPDLOG_NOEXCEPT noexcept
#else
#define SPDLOG_NOEXCEPT throw()
#endif
namespace
spdlog
{
class
formatter
;
namespace
sinks
{
class
sink
;
}
// Common types across the lib
using
log_clock
=
std
::
chrono
::
system_clock
;
using
sink_ptr
=
std
::
shared_ptr
<
sinks
::
sink
>
;
using
sinks_init_list
=
std
::
initializer_list
<
sink_ptr
>
;
using
formatter_ptr
=
std
::
shared_ptr
<
spdlog
::
formatter
>
;
#if defined(SPDLOG_NO_ATOMIC_LEVELS)
using
level_t
=
details
::
null_atomic_int
;
#else
using
level_t
=
std
::
atomic_int
;
#endif
//Log level enum
namespace
level
{
typedef
enum
{
trace
=
0
,
debug
=
1
,
info
=
2
,
notice
=
3
,
warn
=
4
,
err
=
5
,
critical
=
6
,
alert
=
7
,
emerg
=
8
,
off
=
9
}
level_enum
;
static
const
char
*
level_names
[]
{
"trace"
,
"debug"
,
"info"
,
"notice"
,
"warning"
,
"error"
,
"critical"
,
"alert"
,
"emerg"
,
"off"
};
static
const
char
*
short_level_names
[]
{
"T"
,
"D"
,
"I"
,
"N"
,
"W"
,
"E"
,
"C"
,
"A"
,
"M"
,
"O"
};
inline
const
char
*
to_str
(
spdlog
::
level
::
level_enum
l
)
{
return
level_names
[
l
];
}
inline
const
char
*
to_short_str
(
spdlog
::
level
::
level_enum
l
)
{
return
short_level_names
[
l
];
}
}
//level
//
// Async overflow policy - block by default.
//
enum
class
async_overflow_policy
{
block_retry
,
// Block / yield / sleep until message can be enqueued
discard_log_msg
// Discard the message it enqueue fails
};
//
// Log exception
//
class
spdlog_ex
:
public
std
::
exception
{
public:
spdlog_ex
(
const
std
::
string
&
msg
)
:
_msg
(
msg
)
{}
const
char
*
what
()
const
SPDLOG_NOEXCEPT
override
{
return
_msg
.
c_str
();
}
private:
std
::
string
_msg
;
};
//
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
//
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#define SPDLOG_FILENAME_T(s) L ## s
using
filename_t
=
std
::
wstring
;
inline
std
::
string
filename_to_str
(
const
filename_t
&
filename
)
{
std
::
wstring_convert
<
std
::
codecvt_utf8
<
wchar_t
>
,
wchar_t
>
c
;
return
c
.
to_bytes
(
filename
);
}
#else
#define SPDLOG_FILENAME_T(s) s
using
filename_t
=
std
::
string
;
inline
std
::
string
filename_to_str
(
const
filename_t
&
filename
)
{
return
filename
;
}
#endif
}
//spdlog
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <string>
#include <initializer_list>
#include <chrono>
#include <memory>
#include <atomic>
#include <exception>
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#include <codecvt>
#include <locale>
#endif
#include <spdlog/details/null_mutex.h>
//visual studio does not support noexcept yet
#ifndef _MSC_VER
#define SPDLOG_NOEXCEPT noexcept
#else
#define SPDLOG_NOEXCEPT throw()
#endif
namespace
spdlog
{
class
formatter
;
namespace
sinks
{
class
sink
;
}
// Common types across the lib
using
log_clock
=
std
::
chrono
::
system_clock
;
using
sink_ptr
=
std
::
shared_ptr
<
sinks
::
sink
>
;
using
sinks_init_list
=
std
::
initializer_list
<
sink_ptr
>
;
using
formatter_ptr
=
std
::
shared_ptr
<
spdlog
::
formatter
>
;
#if defined(SPDLOG_NO_ATOMIC_LEVELS)
using
level_t
=
details
::
null_atomic_int
;
#else
using
level_t
=
std
::
atomic_int
;
#endif
//Log level enum
namespace
level
{
typedef
enum
{
trace
=
0
,
debug
=
1
,
info
=
2
,
notice
=
3
,
warn
=
4
,
err
=
5
,
critical
=
6
,
alert
=
7
,
emerg
=
8
,
off
=
9
}
level_enum
;
static
const
char
*
level_names
[]
{
"trace"
,
"debug"
,
"info"
,
"notice"
,
"warning"
,
"error"
,
"critical"
,
"alert"
,
"emerg"
,
"off"
};
static
const
char
*
short_level_names
[]
{
"T"
,
"D"
,
"I"
,
"N"
,
"W"
,
"E"
,
"C"
,
"A"
,
"M"
,
"O"
};
inline
const
char
*
to_str
(
spdlog
::
level
::
level_enum
l
)
{
return
level_names
[
l
];
}
inline
const
char
*
to_short_str
(
spdlog
::
level
::
level_enum
l
)
{
return
short_level_names
[
l
];
}
}
//level
//
// Async overflow policy - block by default.
//
enum
class
async_overflow_policy
{
block_retry
,
// Block / yield / sleep until message can be enqueued
discard_log_msg
// Discard the message it enqueue fails
};
//
// Log exception
//
class
spdlog_ex
:
public
std
::
exception
{
public:
spdlog_ex
(
const
std
::
string
&
msg
)
:
_msg
(
msg
)
{}
const
char
*
what
()
const
SPDLOG_NOEXCEPT
override
{
return
_msg
.
c_str
();
}
private:
std
::
string
_msg
;
};
//
// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
//
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#define SPDLOG_FILENAME_T(s) L ## s
using
filename_t
=
std
::
wstring
;
inline
std
::
string
filename_to_str
(
const
filename_t
&
filename
)
{
std
::
wstring_convert
<
std
::
codecvt_utf8
<
wchar_t
>
,
wchar_t
>
c
;
return
c
.
to_bytes
(
filename
);
}
#else
#define SPDLOG_FILENAME_T(s) s
using
filename_t
=
std
::
string
;
inline
std
::
string
filename_to_str
(
const
filename_t
&
filename
)
{
return
filename
;
}
#endif
}
//spdlog
include/spdlog/details/async_log_helper.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
// async log helper :
// Process logs asynchronously using a back thread.
//
// If the internal queue of log messages reaches its max size,
// then the client call will block until there is more room.
//
// If the back thread throws during logging, a spdlog::spdlog_ex exception
// will be thrown in client's thread when tries to log the next message
#pragma once
#include <spdlog/common.h>
#include <spdlog/sinks/sink.h>
#include <spdlog/details/mpmc_bounded_q.h>
#include <spdlog/details/log_msg.h>
#include <spdlog/details/os.h>
#include <spdlog/formatter.h>
#include <chrono>
#include <exception>
#include <functional>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <vector>
namespace
spdlog
{
namespace
details
{
class
async_log_helper
{
// Async msg to move to/from the queue
// Movable only. should never be copied
enum
class
async_msg_type
{
log
,
flush
,
terminate
};
struct
async_msg
{
std
::
string
logger_name
;
level
::
level_enum
level
;
log_clock
::
time_point
time
;
size_t
thread_id
;
std
::
string
txt
;
async_msg_type
msg_type
;
async_msg
()
=
default
;
~
async_msg
()
=
default
;
async_msg
(
async_msg
&&
other
)
SPDLOG_NOEXCEPT
:
logger_name
(
std
::
move
(
other
.
logger_name
)),
level
(
std
::
move
(
other
.
level
)),
time
(
std
::
move
(
other
.
time
)),
txt
(
std
::
move
(
other
.
txt
)),
msg_type
(
std
::
move
(
other
.
msg_type
))
{}
async_msg
(
async_msg_type
m_type
)
:
msg_type
(
m_type
)
{};
async_msg
&
operator
=
(
async_msg
&&
other
)
SPDLOG_NOEXCEPT
{
logger_name
=
std
::
move
(
other
.
logger_name
);
level
=
other
.
level
;
time
=
std
::
move
(
other
.
time
);
thread_id
=
other
.
thread_id
;
txt
=
std
::
move
(
other
.
txt
);
msg_type
=
other
.
msg_type
;
return
*
this
;
}
// never copy or assign. should only be moved..
async_msg
(
const
async_msg
&
)
=
delete
;
async_msg
&
operator
=
(
async_msg
&
other
)
=
delete
;
// construct from log_msg
async_msg
(
const
details
::
log_msg
&
m
)
:
logger_name
(
m
.
logger_name
),
level
(
m
.
level
),
time
(
m
.
time
),
thread_id
(
m
.
thread_id
),
txt
(
m
.
raw
.
data
(),
m
.
raw
.
size
()),
msg_type
(
async_msg_type
::
log
)
{}
// copy into log_msg
void
fill_log_msg
(
log_msg
&
msg
)
{
msg
.
clear
();
msg
.
logger_name
=
logger_name
;
msg
.
level
=
level
;
msg
.
time
=
time
;
msg
.
thread_id
=
thread_id
;
msg
.
raw
<<
txt
;
}
};
public:
using
item_type
=
async_msg
;
using
q_type
=
details
::
mpmc_bounded_queue
<
item_type
>
;
using
clock
=
std
::
chrono
::
steady_clock
;
async_log_helper
(
formatter_ptr
formatter
,
const
std
::
vector
<
sink_ptr
>&
sinks
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
=
async_overflow_policy
::
block_retry
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
=
nullptr
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
=
std
::
chrono
::
milliseconds
::
zero
());
void
log
(
const
details
::
log_msg
&
msg
);
// stop logging and join the back thread
~
async_log_helper
();
void
set_formatter
(
formatter_ptr
);
void
flush
();
private:
formatter_ptr
_formatter
;
std
::
vector
<
std
::
shared_ptr
<
sinks
::
sink
>>
_sinks
;
// queue of messages to log
q_type
_q
;
bool
_flush_requested
;
bool
_terminate_requested
;
// last exception thrown from the worker thread
std
::
shared_ptr
<
spdlog_ex
>
_last_workerthread_ex
;
// overflow policy
const
async_overflow_policy
_overflow_policy
;
// worker thread warmup callback - one can set thread priority, affinity, etc
const
std
::
function
<
void
()
>
_worker_warmup_cb
;
// auto periodic sink flush parameter
const
std
::
chrono
::
milliseconds
_flush_interval_ms
;
// worker thread
std
::
thread
_worker_thread
;
void
push_msg
(
async_msg
&&
new_msg
);
// throw last worker thread exception or if worker thread is not active
void
throw_if_bad_worker
();
// 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
// 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
);
void
handle_flush_interval
(
log_clock
::
time_point
&
now
,
log_clock
::
time_point
&
last_flush
);
// sleep,yield or return immediatly 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
);
};
}
}
///////////////////////////////////////////////////////////////////////////////
// async_sink class implementation
///////////////////////////////////////////////////////////////////////////////
inline
spdlog
::
details
::
async_log_helper
::
async_log_helper
(
formatter_ptr
formatter
,
const
std
::
vector
<
sink_ptr
>&
sinks
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
)
:
_formatter
(
formatter
),
_sinks
(
sinks
),
_q
(
queue_size
),
_flush_requested
(
false
),
_terminate_requested
(
false
),
_overflow_policy
(
overflow_policy
),
_worker_warmup_cb
(
worker_warmup_cb
),
_flush_interval_ms
(
flush_interval_ms
),
_worker_thread
(
&
async_log_helper
::
worker_loop
,
this
)
{}
// Send to the worker thread termination message(level=off)
// and wait for it to finish gracefully
inline
spdlog
::
details
::
async_log_helper
::~
async_log_helper
()
{
try
{
push_msg
(
async_msg
(
async_msg_type
::
terminate
));
_worker_thread
.
join
();
}
catch
(...)
// don't crash in destructor
{}
}
//Try to push and block until succeeded
inline
void
spdlog
::
details
::
async_log_helper
::
log
(
const
details
::
log_msg
&
msg
)
{
push_msg
(
async_msg
(
msg
));
}
//Try to push and block until succeeded
inline
void
spdlog
::
details
::
async_log_helper
::
push_msg
(
details
::
async_log_helper
::
async_msg
&&
new_msg
)
{
throw_if_bad_worker
();
if
(
!
_q
.
enqueue
(
std
::
move
(
new_msg
))
&&
_overflow_policy
!=
async_overflow_policy
::
discard_log_msg
)
{
auto
last_op_time
=
details
::
os
::
now
();
auto
now
=
last_op_time
;
do
{
now
=
details
::
os
::
now
();
sleep_or_yield
(
now
,
last_op_time
);
}
while
(
!
_q
.
enqueue
(
std
::
move
(
new_msg
)));
}
}
inline
void
spdlog
::
details
::
async_log_helper
::
flush
()
{
push_msg
(
async_msg
(
async_msg_type
::
flush
));
}
inline
void
spdlog
::
details
::
async_log_helper
::
worker_loop
()
{
try
{
if
(
_worker_warmup_cb
)
_worker_warmup_cb
();
auto
last_pop
=
details
::
os
::
now
();
auto
last_flush
=
last_pop
;
while
(
process_next_msg
(
last_pop
,
last_flush
));
}
catch
(
const
std
::
exception
&
ex
)
{
_last_workerthread_ex
=
std
::
make_shared
<
spdlog_ex
>
(
std
::
string
(
"async_logger worker thread exception: "
)
+
ex
.
what
());
}
catch
(...)
{
_last_workerthread_ex
=
std
::
make_shared
<
spdlog_ex
>
(
"async_logger worker thread exception"
);
}
}
// process next message in the queue
// return true if this thread should still be active (no msg with level::off was received)
inline
bool
spdlog
::
details
::
async_log_helper
::
process_next_msg
(
log_clock
::
time_point
&
last_pop
,
log_clock
::
time_point
&
last_flush
)
{
async_msg
incoming_async_msg
;
log_msg
incoming_log_msg
;
if
(
_q
.
dequeue
(
incoming_async_msg
))
{
last_pop
=
details
::
os
::
now
();
switch
(
incoming_async_msg
.
msg_type
)
{
case
async_msg_type
:
:
flush
:
_flush_requested
=
true
;
break
;
case
async_msg_type
:
:
terminate
:
_flush_requested
=
true
;
_terminate_requested
=
true
;
break
;
default:
incoming_async_msg
.
fill_log_msg
(
incoming_log_msg
);
_formatter
->
format
(
incoming_log_msg
);
for
(
auto
&
s
:
_sinks
)
s
->
log
(
incoming_log_msg
);
}
return
true
;
}
// Handle empty queue..
// This is the only place where the queue can terminate or flush to avoid losing messages already in the queue
else
{
auto
now
=
details
::
os
::
now
();
handle_flush_interval
(
now
,
last_flush
);
sleep_or_yield
(
now
,
last_pop
);
return
!
_terminate_requested
;
}
}
inline
void
spdlog
::
details
::
async_log_helper
::
handle_flush_interval
(
log_clock
::
time_point
&
now
,
log_clock
::
time_point
&
last_flush
)
{
auto
should_flush
=
_flush_requested
||
(
_flush_interval_ms
!=
std
::
chrono
::
milliseconds
::
zero
()
&&
now
-
last_flush
>=
_flush_interval_ms
);
if
(
should_flush
)
{
for
(
auto
&
s
:
_sinks
)
s
->
flush
();
now
=
last_flush
=
details
::
os
::
now
();
_flush_requested
=
false
;
}
}
inline
void
spdlog
::
details
::
async_log_helper
::
set_formatter
(
formatter_ptr
msg_formatter
)
{
_formatter
=
msg_formatter
;
}
// sleep,yield or return immediatly using 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
::
milliseconds
;
using
namespace
std
::
this_thread
;
auto
time_since_op
=
now
-
last_op_time
;
// spin upto 1 ms
if
(
time_since_op
<=
milliseconds
(
1
))
return
;
// yield upto 10ms
if
(
time_since_op
<=
milliseconds
(
10
))
return
yield
();
// sleep for half of duration since last op
if
(
time_since_op
<=
milliseconds
(
100
))
return
sleep_for
(
time_since_op
/
2
);
return
sleep_for
(
milliseconds
(
100
));
}
// throw if the worker thread threw an exception or not active
inline
void
spdlog
::
details
::
async_log_helper
::
throw_if_bad_worker
()
{
if
(
_last_workerthread_ex
)
{
auto
ex
=
std
::
move
(
_last_workerthread_ex
);
throw
*
ex
;
}
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
// async log helper :
// Process logs asynchronously using a back thread.
//
// If the internal queue of log messages reaches its max size,
// then the client call will block until there is more room.
//
// If the back thread throws during logging, a spdlog::spdlog_ex exception
// will be thrown in client's thread when tries to log the next message
#pragma once
#include <spdlog/common.h>
#include <spdlog/sinks/sink.h>
#include <spdlog/details/mpmc_bounded_q.h>
#include <spdlog/details/log_msg.h>
#include <spdlog/details/os.h>
#include <spdlog/formatter.h>
#include <chrono>
#include <exception>
#include <functional>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <vector>
namespace
spdlog
{
namespace
details
{
class
async_log_helper
{
// Async msg to move to/from the queue
// Movable only. should never be copied
enum
class
async_msg_type
{
log
,
flush
,
terminate
};
struct
async_msg
{
std
::
string
logger_name
;
level
::
level_enum
level
;
log_clock
::
time_point
time
;
size_t
thread_id
;
std
::
string
txt
;
async_msg_type
msg_type
;
async_msg
()
=
default
;
~
async_msg
()
=
default
;
async_msg
(
async_msg
&&
other
)
SPDLOG_NOEXCEPT
:
logger_name
(
std
::
move
(
other
.
logger_name
)),
level
(
std
::
move
(
other
.
level
)),
time
(
std
::
move
(
other
.
time
)),
txt
(
std
::
move
(
other
.
txt
)),
msg_type
(
std
::
move
(
other
.
msg_type
))
{}
async_msg
(
async_msg_type
m_type
)
:
msg_type
(
m_type
)
{};
async_msg
&
operator
=
(
async_msg
&&
other
)
SPDLOG_NOEXCEPT
{
logger_name
=
std
::
move
(
other
.
logger_name
);
level
=
other
.
level
;
time
=
std
::
move
(
other
.
time
);
thread_id
=
other
.
thread_id
;
txt
=
std
::
move
(
other
.
txt
);
msg_type
=
other
.
msg_type
;
return
*
this
;
}
// never copy or assign. should only be moved..
async_msg
(
const
async_msg
&
)
=
delete
;
async_msg
&
operator
=
(
async_msg
&
other
)
=
delete
;
// construct from log_msg
async_msg
(
const
details
::
log_msg
&
m
)
:
logger_name
(
m
.
logger_name
),
level
(
m
.
level
),
time
(
m
.
time
),
thread_id
(
m
.
thread_id
),
txt
(
m
.
raw
.
data
(),
m
.
raw
.
size
()),
msg_type
(
async_msg_type
::
log
)
{}
// copy into log_msg
void
fill_log_msg
(
log_msg
&
msg
)
{
msg
.
clear
();
msg
.
logger_name
=
logger_name
;
msg
.
level
=
level
;
msg
.
time
=
time
;
msg
.
thread_id
=
thread_id
;
msg
.
raw
<<
txt
;
}
};
public:
using
item_type
=
async_msg
;
using
q_type
=
details
::
mpmc_bounded_queue
<
item_type
>
;
using
clock
=
std
::
chrono
::
steady_clock
;
async_log_helper
(
formatter_ptr
formatter
,
const
std
::
vector
<
sink_ptr
>&
sinks
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
=
async_overflow_policy
::
block_retry
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
=
nullptr
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
=
std
::
chrono
::
milliseconds
::
zero
());
void
log
(
const
details
::
log_msg
&
msg
);
// stop logging and join the back thread
~
async_log_helper
();
void
set_formatter
(
formatter_ptr
);
void
flush
();
private:
formatter_ptr
_formatter
;
std
::
vector
<
std
::
shared_ptr
<
sinks
::
sink
>>
_sinks
;
// queue of messages to log
q_type
_q
;
bool
_flush_requested
;
bool
_terminate_requested
;
// last exception thrown from the worker thread
std
::
shared_ptr
<
spdlog_ex
>
_last_workerthread_ex
;
// overflow policy
const
async_overflow_policy
_overflow_policy
;
// worker thread warmup callback - one can set thread priority, affinity, etc
const
std
::
function
<
void
()
>
_worker_warmup_cb
;
// auto periodic sink flush parameter
const
std
::
chrono
::
milliseconds
_flush_interval_ms
;
// worker thread
std
::
thread
_worker_thread
;
void
push_msg
(
async_msg
&&
new_msg
);
// throw last worker thread exception or if worker thread is not active
void
throw_if_bad_worker
();
// 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
// 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
);
void
handle_flush_interval
(
log_clock
::
time_point
&
now
,
log_clock
::
time_point
&
last_flush
);
// sleep,yield or return immediatly 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
);
};
}
}
///////////////////////////////////////////////////////////////////////////////
// async_sink class implementation
///////////////////////////////////////////////////////////////////////////////
inline
spdlog
::
details
::
async_log_helper
::
async_log_helper
(
formatter_ptr
formatter
,
const
std
::
vector
<
sink_ptr
>&
sinks
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
)
:
_formatter
(
formatter
),
_sinks
(
sinks
),
_q
(
queue_size
),
_flush_requested
(
false
),
_terminate_requested
(
false
),
_overflow_policy
(
overflow_policy
),
_worker_warmup_cb
(
worker_warmup_cb
),
_flush_interval_ms
(
flush_interval_ms
),
_worker_thread
(
&
async_log_helper
::
worker_loop
,
this
)
{}
// Send to the worker thread termination message(level=off)
// and wait for it to finish gracefully
inline
spdlog
::
details
::
async_log_helper
::~
async_log_helper
()
{
try
{
push_msg
(
async_msg
(
async_msg_type
::
terminate
));
_worker_thread
.
join
();
}
catch
(...)
// don't crash in destructor
{}
}
//Try to push and block until succeeded
inline
void
spdlog
::
details
::
async_log_helper
::
log
(
const
details
::
log_msg
&
msg
)
{
push_msg
(
async_msg
(
msg
));
}
//Try to push and block until succeeded
inline
void
spdlog
::
details
::
async_log_helper
::
push_msg
(
details
::
async_log_helper
::
async_msg
&&
new_msg
)
{
throw_if_bad_worker
();
if
(
!
_q
.
enqueue
(
std
::
move
(
new_msg
))
&&
_overflow_policy
!=
async_overflow_policy
::
discard_log_msg
)
{
auto
last_op_time
=
details
::
os
::
now
();
auto
now
=
last_op_time
;
do
{
now
=
details
::
os
::
now
();
sleep_or_yield
(
now
,
last_op_time
);
}
while
(
!
_q
.
enqueue
(
std
::
move
(
new_msg
)));
}
}
inline
void
spdlog
::
details
::
async_log_helper
::
flush
()
{
push_msg
(
async_msg
(
async_msg_type
::
flush
));
}
inline
void
spdlog
::
details
::
async_log_helper
::
worker_loop
()
{
try
{
if
(
_worker_warmup_cb
)
_worker_warmup_cb
();
auto
last_pop
=
details
::
os
::
now
();
auto
last_flush
=
last_pop
;
while
(
process_next_msg
(
last_pop
,
last_flush
));
}
catch
(
const
std
::
exception
&
ex
)
{
_last_workerthread_ex
=
std
::
make_shared
<
spdlog_ex
>
(
std
::
string
(
"async_logger worker thread exception: "
)
+
ex
.
what
());
}
catch
(...)
{
_last_workerthread_ex
=
std
::
make_shared
<
spdlog_ex
>
(
"async_logger worker thread exception"
);
}
}
// process next message in the queue
// return true if this thread should still be active (no msg with level::off was received)
inline
bool
spdlog
::
details
::
async_log_helper
::
process_next_msg
(
log_clock
::
time_point
&
last_pop
,
log_clock
::
time_point
&
last_flush
)
{
async_msg
incoming_async_msg
;
log_msg
incoming_log_msg
;
if
(
_q
.
dequeue
(
incoming_async_msg
))
{
last_pop
=
details
::
os
::
now
();
switch
(
incoming_async_msg
.
msg_type
)
{
case
async_msg_type
:
:
flush
:
_flush_requested
=
true
;
break
;
case
async_msg_type
:
:
terminate
:
_flush_requested
=
true
;
_terminate_requested
=
true
;
break
;
default:
incoming_async_msg
.
fill_log_msg
(
incoming_log_msg
);
_formatter
->
format
(
incoming_log_msg
);
for
(
auto
&
s
:
_sinks
)
s
->
log
(
incoming_log_msg
);
}
return
true
;
}
// Handle empty queue..
// This is the only place where the queue can terminate or flush to avoid losing messages already in the queue
else
{
auto
now
=
details
::
os
::
now
();
handle_flush_interval
(
now
,
last_flush
);
sleep_or_yield
(
now
,
last_pop
);
return
!
_terminate_requested
;
}
}
inline
void
spdlog
::
details
::
async_log_helper
::
handle_flush_interval
(
log_clock
::
time_point
&
now
,
log_clock
::
time_point
&
last_flush
)
{
auto
should_flush
=
_flush_requested
||
(
_flush_interval_ms
!=
std
::
chrono
::
milliseconds
::
zero
()
&&
now
-
last_flush
>=
_flush_interval_ms
);
if
(
should_flush
)
{
for
(
auto
&
s
:
_sinks
)
s
->
flush
();
now
=
last_flush
=
details
::
os
::
now
();
_flush_requested
=
false
;
}
}
inline
void
spdlog
::
details
::
async_log_helper
::
set_formatter
(
formatter_ptr
msg_formatter
)
{
_formatter
=
msg_formatter
;
}
// sleep,yield or return immediatly using 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
::
milliseconds
;
using
namespace
std
::
this_thread
;
auto
time_since_op
=
now
-
last_op_time
;
// spin upto 1 ms
if
(
time_since_op
<=
milliseconds
(
1
))
return
;
// yield upto 10ms
if
(
time_since_op
<=
milliseconds
(
10
))
return
yield
();
// sleep for half of duration since last op
if
(
time_since_op
<=
milliseconds
(
100
))
return
sleep_for
(
time_since_op
/
2
);
return
sleep_for
(
milliseconds
(
100
));
}
// throw if the worker thread threw an exception or not active
inline
void
spdlog
::
details
::
async_log_helper
::
throw_if_bad_worker
()
{
if
(
_last_workerthread_ex
)
{
auto
ex
=
std
::
move
(
_last_workerthread_ex
);
throw
*
ex
;
}
}
include/spdlog/details/async_logger_impl.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Async Logger implementation
// Use an async_sink (queue per logger) to perform the logging in a worker thread
#include <spdlog/details/async_log_helper.h>
#include <spdlog/async_logger.h>
#include <string>
#include <functional>
#include <chrono>
#include <memory>
template
<
class
It
>
inline
spdlog
::
async_logger
::
async_logger
(
const
std
::
string
&
logger_name
,
const
It
&
begin
,
const
It
&
end
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
)
:
logger
(
logger_name
,
begin
,
end
),
_async_log_helper
(
new
details
::
async_log_helper
(
_formatter
,
_sinks
,
queue_size
,
overflow_policy
,
worker_warmup_cb
,
flush_interval_ms
))
{
}
inline
spdlog
::
async_logger
::
async_logger
(
const
std
::
string
&
logger_name
,
sinks_init_list
sinks
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
)
:
async_logger
(
logger_name
,
sinks
.
begin
(),
sinks
.
end
(),
queue_size
,
overflow_policy
,
worker_warmup_cb
,
flush_interval_ms
)
{}
inline
spdlog
::
async_logger
::
async_logger
(
const
std
::
string
&
logger_name
,
sink_ptr
single_sink
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
)
:
async_logger
(
logger_name
,
{
single_sink
},
queue_size
,
overflow_policy
,
worker_warmup_cb
,
flush_interval_ms
)
{}
inline
void
spdlog
::
async_logger
::
flush
()
{
_async_log_helper
->
flush
();
}
inline
void
spdlog
::
async_logger
::
_set_formatter
(
spdlog
::
formatter_ptr
msg_formatter
)
{
_formatter
=
msg_formatter
;
_async_log_helper
->
set_formatter
(
_formatter
);
}
inline
void
spdlog
::
async_logger
::
_set_pattern
(
const
std
::
string
&
pattern
)
{
_formatter
=
std
::
make_shared
<
pattern_formatter
>
(
pattern
);
_async_log_helper
->
set_formatter
(
_formatter
);
}
inline
void
spdlog
::
async_logger
::
_log_msg
(
details
::
log_msg
&
msg
)
{
_async_log_helper
->
log
(
msg
);
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Async Logger implementation
// Use an async_sink (queue per logger) to perform the logging in a worker thread
#include <spdlog/details/async_log_helper.h>
#include <spdlog/async_logger.h>
#include <string>
#include <functional>
#include <chrono>
#include <memory>
template
<
class
It
>
inline
spdlog
::
async_logger
::
async_logger
(
const
std
::
string
&
logger_name
,
const
It
&
begin
,
const
It
&
end
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
)
:
logger
(
logger_name
,
begin
,
end
),
_async_log_helper
(
new
details
::
async_log_helper
(
_formatter
,
_sinks
,
queue_size
,
overflow_policy
,
worker_warmup_cb
,
flush_interval_ms
))
{
}
inline
spdlog
::
async_logger
::
async_logger
(
const
std
::
string
&
logger_name
,
sinks_init_list
sinks
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
)
:
async_logger
(
logger_name
,
sinks
.
begin
(),
sinks
.
end
(),
queue_size
,
overflow_policy
,
worker_warmup_cb
,
flush_interval_ms
)
{}
inline
spdlog
::
async_logger
::
async_logger
(
const
std
::
string
&
logger_name
,
sink_ptr
single_sink
,
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
)
:
async_logger
(
logger_name
,
{
single_sink
},
queue_size
,
overflow_policy
,
worker_warmup_cb
,
flush_interval_ms
)
{}
inline
void
spdlog
::
async_logger
::
flush
()
{
_async_log_helper
->
flush
();
}
inline
void
spdlog
::
async_logger
::
_set_formatter
(
spdlog
::
formatter_ptr
msg_formatter
)
{
_formatter
=
msg_formatter
;
_async_log_helper
->
set_formatter
(
_formatter
);
}
inline
void
spdlog
::
async_logger
::
_set_pattern
(
const
std
::
string
&
pattern
)
{
_formatter
=
std
::
make_shared
<
pattern_formatter
>
(
pattern
);
_async_log_helper
->
set_formatter
(
_formatter
);
}
inline
void
spdlog
::
async_logger
::
_log_msg
(
details
::
log_msg
&
msg
)
{
_async_log_helper
->
log
(
msg
);
}
include/spdlog/details/file_helper.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Helper class for file sink
// When failing to open a file, retry several times(5) with small delay between the tries(10 ms)
// Can be set to auto flush on every line
// Throw spdlog_ex exception on errors
#include <spdlog/details/os.h>
#include <spdlog/details/log_msg.h>
#include <chrono>
#include <cstdio>
#include <string>
#include <thread>
namespace
spdlog
{
namespace
details
{
class
file_helper
{
public:
const
int
open_tries
=
5
;
const
int
open_interval
=
10
;
explicit
file_helper
(
bool
force_flush
)
:
_fd
(
nullptr
),
_force_flush
(
force_flush
)
{}
file_helper
(
const
file_helper
&
)
=
delete
;
file_helper
&
operator
=
(
const
file_helper
&
)
=
delete
;
~
file_helper
()
{
close
();
}
void
open
(
const
filename_t
&
fname
,
bool
truncate
=
false
)
{
close
();
auto
*
mode
=
truncate
?
SPDLOG_FILENAME_T
(
"wb"
)
:
SPDLOG_FILENAME_T
(
"ab"
);
_filename
=
fname
;
for
(
int
tries
=
0
;
tries
<
open_tries
;
++
tries
)
{
if
(
!
os
::
fopen_s
(
&
_fd
,
fname
,
mode
))
return
;
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
open_interval
));
}
throw
spdlog_ex
(
"Failed opening file "
+
filename_to_str
(
_filename
)
+
" for writing"
);
}
void
reopen
(
bool
truncate
)
{
if
(
_filename
.
empty
())
throw
spdlog_ex
(
"Failed re opening file - was not opened before"
);
open
(
_filename
,
truncate
);
}
void
flush
()
{
std
::
fflush
(
_fd
);
}
void
close
()
{
if
(
_fd
)
{
std
::
fclose
(
_fd
);
_fd
=
nullptr
;
}
}
void
write
(
const
log_msg
&
msg
)
{
size_t
msg_size
=
msg
.
formatted
.
size
();
auto
data
=
msg
.
formatted
.
data
();
if
(
std
::
fwrite
(
data
,
1
,
msg_size
,
_fd
)
!=
msg_size
)
throw
spdlog_ex
(
"Failed writing to file "
+
filename_to_str
(
_filename
));
if
(
_force_flush
)
std
::
fflush
(
_fd
);
}
long
size
()
{
if
(
!
_fd
)
throw
spdlog_ex
(
"Cannot use size() on closed file "
+
filename_to_str
(
_filename
));
auto
pos
=
ftell
(
_fd
);
if
(
fseek
(
_fd
,
0
,
SEEK_END
)
!=
0
)
throw
spdlog_ex
(
"fseek failed on file "
+
filename_to_str
(
_filename
));
auto
file_size
=
ftell
(
_fd
);
if
(
fseek
(
_fd
,
pos
,
SEEK_SET
)
!=
0
)
throw
spdlog_ex
(
"fseek failed on file "
+
filename_to_str
(
_filename
));
if
(
file_size
==
-
1
)
throw
spdlog_ex
(
"ftell failed on file "
+
filename_to_str
(
_filename
));
return
file_size
;
}
const
filename_t
&
filename
()
const
{
return
_filename
;
}
static
bool
file_exists
(
const
filename_t
&
name
)
{
return
os
::
file_exists
(
name
);
}
private:
FILE
*
_fd
;
filename_t
_filename
;
bool
_force_flush
;
};
}
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Helper class for file sink
// When failing to open a file, retry several times(5) with small delay between the tries(10 ms)
// Can be set to auto flush on every line
// Throw spdlog_ex exception on errors
#include <spdlog/details/os.h>
#include <spdlog/details/log_msg.h>
#include <chrono>
#include <cstdio>
#include <string>
#include <thread>
namespace
spdlog
{
namespace
details
{
class
file_helper
{
public:
const
int
open_tries
=
5
;
const
int
open_interval
=
10
;
explicit
file_helper
(
bool
force_flush
)
:
_fd
(
nullptr
),
_force_flush
(
force_flush
)
{}
file_helper
(
const
file_helper
&
)
=
delete
;
file_helper
&
operator
=
(
const
file_helper
&
)
=
delete
;
~
file_helper
()
{
close
();
}
void
open
(
const
filename_t
&
fname
,
bool
truncate
=
false
)
{
close
();
auto
*
mode
=
truncate
?
SPDLOG_FILENAME_T
(
"wb"
)
:
SPDLOG_FILENAME_T
(
"ab"
);
_filename
=
fname
;
for
(
int
tries
=
0
;
tries
<
open_tries
;
++
tries
)
{
if
(
!
os
::
fopen_s
(
&
_fd
,
fname
,
mode
))
return
;
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
milliseconds
(
open_interval
));
}
throw
spdlog_ex
(
"Failed opening file "
+
filename_to_str
(
_filename
)
+
" for writing"
);
}
void
reopen
(
bool
truncate
)
{
if
(
_filename
.
empty
())
throw
spdlog_ex
(
"Failed re opening file - was not opened before"
);
open
(
_filename
,
truncate
);
}
void
flush
()
{
std
::
fflush
(
_fd
);
}
void
close
()
{
if
(
_fd
)
{
std
::
fclose
(
_fd
);
_fd
=
nullptr
;
}
}
void
write
(
const
log_msg
&
msg
)
{
size_t
msg_size
=
msg
.
formatted
.
size
();
auto
data
=
msg
.
formatted
.
data
();
if
(
std
::
fwrite
(
data
,
1
,
msg_size
,
_fd
)
!=
msg_size
)
throw
spdlog_ex
(
"Failed writing to file "
+
filename_to_str
(
_filename
));
if
(
_force_flush
)
std
::
fflush
(
_fd
);
}
long
size
()
{
if
(
!
_fd
)
throw
spdlog_ex
(
"Cannot use size() on closed file "
+
filename_to_str
(
_filename
));
auto
pos
=
ftell
(
_fd
);
if
(
fseek
(
_fd
,
0
,
SEEK_END
)
!=
0
)
throw
spdlog_ex
(
"fseek failed on file "
+
filename_to_str
(
_filename
));
auto
file_size
=
ftell
(
_fd
);
if
(
fseek
(
_fd
,
pos
,
SEEK_SET
)
!=
0
)
throw
spdlog_ex
(
"fseek failed on file "
+
filename_to_str
(
_filename
));
if
(
file_size
==
-
1
)
throw
spdlog_ex
(
"ftell failed on file "
+
filename_to_str
(
_filename
));
return
file_size
;
}
const
filename_t
&
filename
()
const
{
return
_filename
;
}
static
bool
file_exists
(
const
filename_t
&
name
)
{
return
os
::
file_exists
(
name
);
}
private:
FILE
*
_fd
;
filename_t
_filename
;
bool
_force_flush
;
};
}
}
include/spdlog/details/format.h
View file @
0d263598
This source diff could not be displayed because it is too large. You can
view the blob
instead.
include/spdlog/details/line_logger_fwd.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/common.h>
#include <spdlog/details/log_msg.h>
#include <string>
// Line logger class - aggregates operator<< calls to fast ostream
// and logs upon destruction
namespace
spdlog
{
// Forward declaration
class
logger
;
namespace
details
{
class
line_logger
{
public:
line_logger
(
logger
*
callback_logger
,
level
::
level_enum
msg_level
,
bool
enabled
);
// 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
);
//Log the log message using the callback logger
~
line_logger
();
//
// Support for format string with variadic args
//
void
write
(
const
char
*
what
);
template
<
typename
...
Args
>
void
write
(
const
char
*
fmt
,
const
Args
&
...
args
);
//
// Support for operator<<
//
line_logger
&
operator
<<
(
const
char
*
what
);
line_logger
&
operator
<<
(
const
std
::
string
&
what
);
line_logger
&
operator
<<
(
int
what
);
line_logger
&
operator
<<
(
unsigned
int
what
);
line_logger
&
operator
<<
(
long
what
);
line_logger
&
operator
<<
(
unsigned
long
what
);
line_logger
&
operator
<<
(
long
long
what
);
line_logger
&
operator
<<
(
unsigned
long
long
what
);
line_logger
&
operator
<<
(
double
what
);
line_logger
&
operator
<<
(
long
double
what
);
line_logger
&
operator
<<
(
float
what
);
line_logger
&
operator
<<
(
char
what
);
//Support user types which implements operator<<
template
<
typename
T
>
line_logger
&
operator
<<
(
const
T
&
what
);
void
disable
();
bool
is_enabled
()
const
;
private:
logger
*
_callback_logger
;
log_msg
_log_msg
;
bool
_enabled
;
};
}
//Namespace details
}
// Namespace spdlog
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/common.h>
#include <spdlog/details/log_msg.h>
#include <string>
// Line logger class - aggregates operator<< calls to fast ostream
// and logs upon destruction
namespace
spdlog
{
// Forward declaration
class
logger
;
namespace
details
{
class
line_logger
{
public:
line_logger
(
logger
*
callback_logger
,
level
::
level_enum
msg_level
,
bool
enabled
);
// 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
);
//Log the log message using the callback logger
~
line_logger
();
//
// Support for format string with variadic args
//
void
write
(
const
char
*
what
);
template
<
typename
...
Args
>
void
write
(
const
char
*
fmt
,
const
Args
&
...
args
);
//
// Support for operator<<
//
line_logger
&
operator
<<
(
const
char
*
what
);
line_logger
&
operator
<<
(
const
std
::
string
&
what
);
line_logger
&
operator
<<
(
int
what
);
line_logger
&
operator
<<
(
unsigned
int
what
);
line_logger
&
operator
<<
(
long
what
);
line_logger
&
operator
<<
(
unsigned
long
what
);
line_logger
&
operator
<<
(
long
long
what
);
line_logger
&
operator
<<
(
unsigned
long
long
what
);
line_logger
&
operator
<<
(
double
what
);
line_logger
&
operator
<<
(
long
double
what
);
line_logger
&
operator
<<
(
float
what
);
line_logger
&
operator
<<
(
char
what
);
//Support user types which implements operator<<
template
<
typename
T
>
line_logger
&
operator
<<
(
const
T
&
what
);
void
disable
();
bool
is_enabled
()
const
;
private:
logger
*
_callback_logger
;
log_msg
_log_msg
;
bool
_enabled
;
};
}
//Namespace details
}
// Namespace spdlog
include/spdlog/details/line_logger_impl.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <type_traits>
#include <spdlog/details/line_logger_fwd.h>
#include <spdlog/common.h>
#include <spdlog/logger.h>
#include <string>
#include <utility>
// Line logger class - aggregates operator<< calls to fast ostream
// and logs upon destruction
inline
spdlog
::
details
::
line_logger
::
line_logger
(
logger
*
callback_logger
,
level
::
level_enum
msg_level
,
bool
enabled
)
:
_callback_logger
(
callback_logger
),
_log_msg
(
msg_level
),
_enabled
(
enabled
)
{}
inline
spdlog
::
details
::
line_logger
::
line_logger
(
line_logger
&&
other
)
:
_callback_logger
(
other
.
_callback_logger
),
_log_msg
(
std
::
move
(
other
.
_log_msg
)),
_enabled
(
other
.
_enabled
)
{
other
.
disable
();
}
//Log the log message using the callback logger
inline
spdlog
::
details
::
line_logger
::~
line_logger
()
{
if
(
_enabled
)
{
#ifndef SPDLOG_NO_NAME
_log_msg
.
logger_name
=
_callback_logger
->
name
();
#endif
#ifndef SPDLOG_NO_DATETIME
_log_msg
.
time
=
os
::
now
();
#endif
#ifndef SPDLOG_NO_THREAD_ID
_log_msg
.
thread_id
=
os
::
thread_id
();
#endif
_callback_logger
->
_log_msg
(
_log_msg
);
}
}
//
// Support for format string with variadic args
//
inline
void
spdlog
::
details
::
line_logger
::
write
(
const
char
*
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
}
template
<
typename
...
Args
>
inline
void
spdlog
::
details
::
line_logger
::
write
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
if
(
!
_enabled
)
return
;
try
{
_log_msg
.
raw
.
write
(
fmt
,
args
...);
}
catch
(
const
fmt
::
FormatError
&
e
)
{
throw
spdlog_ex
(
fmt
::
format
(
"formatting error while processing format string '{}': {}"
,
fmt
,
e
.
what
()));
}
}
//
// Support for operator<<
//
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
const
char
*
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
const
std
::
string
&
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
int
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
unsigned
int
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
long
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
unsigned
long
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
long
long
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
unsigned
long
long
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
double
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
long
double
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
float
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
char
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
//Support user types which implements operator<<
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
const
T
&
what
)
{
if
(
_enabled
)
_log_msg
.
raw
.
write
(
"{}"
,
what
);
return
*
this
;
}
inline
void
spdlog
::
details
::
line_logger
::
disable
()
{
_enabled
=
false
;
}
inline
bool
spdlog
::
details
::
line_logger
::
is_enabled
()
const
{
return
_enabled
;
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <type_traits>
#include <spdlog/details/line_logger_fwd.h>
#include <spdlog/common.h>
#include <spdlog/logger.h>
#include <string>
#include <utility>
// Line logger class - aggregates operator<< calls to fast ostream
// and logs upon destruction
inline
spdlog
::
details
::
line_logger
::
line_logger
(
logger
*
callback_logger
,
level
::
level_enum
msg_level
,
bool
enabled
)
:
_callback_logger
(
callback_logger
),
_log_msg
(
msg_level
),
_enabled
(
enabled
)
{}
inline
spdlog
::
details
::
line_logger
::
line_logger
(
line_logger
&&
other
)
:
_callback_logger
(
other
.
_callback_logger
),
_log_msg
(
std
::
move
(
other
.
_log_msg
)),
_enabled
(
other
.
_enabled
)
{
other
.
disable
();
}
//Log the log message using the callback logger
inline
spdlog
::
details
::
line_logger
::~
line_logger
()
{
if
(
_enabled
)
{
#ifndef SPDLOG_NO_NAME
_log_msg
.
logger_name
=
_callback_logger
->
name
();
#endif
#ifndef SPDLOG_NO_DATETIME
_log_msg
.
time
=
os
::
now
();
#endif
#ifndef SPDLOG_NO_THREAD_ID
_log_msg
.
thread_id
=
os
::
thread_id
();
#endif
_callback_logger
->
_log_msg
(
_log_msg
);
}
}
//
// Support for format string with variadic args
//
inline
void
spdlog
::
details
::
line_logger
::
write
(
const
char
*
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
}
template
<
typename
...
Args
>
inline
void
spdlog
::
details
::
line_logger
::
write
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
if
(
!
_enabled
)
return
;
try
{
_log_msg
.
raw
.
write
(
fmt
,
args
...);
}
catch
(
const
fmt
::
FormatError
&
e
)
{
throw
spdlog_ex
(
fmt
::
format
(
"formatting error while processing format string '{}': {}"
,
fmt
,
e
.
what
()));
}
}
//
// Support for operator<<
//
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
const
char
*
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
const
std
::
string
&
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
int
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
unsigned
int
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
long
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
unsigned
long
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
long
long
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
unsigned
long
long
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
double
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
long
double
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
float
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
char
what
)
{
if
(
_enabled
)
_log_msg
.
raw
<<
what
;
return
*
this
;
}
//Support user types which implements operator<<
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
&
spdlog
::
details
::
line_logger
::
operator
<<
(
const
T
&
what
)
{
if
(
_enabled
)
_log_msg
.
raw
.
write
(
"{}"
,
what
);
return
*
this
;
}
inline
void
spdlog
::
details
::
line_logger
::
disable
()
{
_enabled
=
false
;
}
inline
bool
spdlog
::
details
::
line_logger
::
is_enabled
()
const
{
return
_enabled
;
}
include/spdlog/details/log_msg.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/common.h>
#include <spdlog/details/format.h>
#include <string>
#include <utility>
namespace
spdlog
{
namespace
details
{
struct
log_msg
{
log_msg
()
=
default
;
log_msg
(
level
::
level_enum
l
)
:
logger_name
(),
level
(
l
),
raw
(),
formatted
()
{}
log_msg
(
const
log_msg
&
other
)
:
logger_name
(
other
.
logger_name
),
level
(
other
.
level
),
time
(
other
.
time
),
thread_id
(
other
.
thread_id
)
{
if
(
other
.
raw
.
size
())
raw
<<
fmt
::
BasicStringRef
<
char
>
(
other
.
raw
.
data
(),
other
.
raw
.
size
());
if
(
other
.
formatted
.
size
())
formatted
<<
fmt
::
BasicStringRef
<
char
>
(
other
.
formatted
.
data
(),
other
.
formatted
.
size
());
}
log_msg
(
log_msg
&&
other
)
:
logger_name
(
std
::
move
(
other
.
logger_name
)),
level
(
other
.
level
),
time
(
std
::
move
(
other
.
time
)),
thread_id
(
other
.
thread_id
),
raw
(
std
::
move
(
other
.
raw
)),
formatted
(
std
::
move
(
other
.
formatted
))
{
other
.
clear
();
}
log_msg
&
operator
=
(
log_msg
&&
other
)
{
if
(
this
==
&
other
)
return
*
this
;
logger_name
=
std
::
move
(
other
.
logger_name
);
level
=
other
.
level
;
time
=
std
::
move
(
other
.
time
);
thread_id
=
other
.
thread_id
;
raw
=
std
::
move
(
other
.
raw
);
formatted
=
std
::
move
(
other
.
formatted
);
other
.
clear
();
return
*
this
;
}
void
clear
()
{
level
=
level
::
off
;
raw
.
clear
();
formatted
.
clear
();
}
std
::
string
logger_name
;
level
::
level_enum
level
;
log_clock
::
time_point
time
;
size_t
thread_id
;
fmt
::
MemoryWriter
raw
;
fmt
::
MemoryWriter
formatted
;
};
}
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/common.h>
#include <spdlog/details/format.h>
#include <string>
#include <utility>
namespace
spdlog
{
namespace
details
{
struct
log_msg
{
log_msg
()
=
default
;
log_msg
(
level
::
level_enum
l
)
:
logger_name
(),
level
(
l
),
raw
(),
formatted
()
{}
log_msg
(
const
log_msg
&
other
)
:
logger_name
(
other
.
logger_name
),
level
(
other
.
level
),
time
(
other
.
time
),
thread_id
(
other
.
thread_id
)
{
if
(
other
.
raw
.
size
())
raw
<<
fmt
::
BasicStringRef
<
char
>
(
other
.
raw
.
data
(),
other
.
raw
.
size
());
if
(
other
.
formatted
.
size
())
formatted
<<
fmt
::
BasicStringRef
<
char
>
(
other
.
formatted
.
data
(),
other
.
formatted
.
size
());
}
log_msg
(
log_msg
&&
other
)
:
logger_name
(
std
::
move
(
other
.
logger_name
)),
level
(
other
.
level
),
time
(
std
::
move
(
other
.
time
)),
thread_id
(
other
.
thread_id
),
raw
(
std
::
move
(
other
.
raw
)),
formatted
(
std
::
move
(
other
.
formatted
))
{
other
.
clear
();
}
log_msg
&
operator
=
(
log_msg
&&
other
)
{
if
(
this
==
&
other
)
return
*
this
;
logger_name
=
std
::
move
(
other
.
logger_name
);
level
=
other
.
level
;
time
=
std
::
move
(
other
.
time
);
thread_id
=
other
.
thread_id
;
raw
=
std
::
move
(
other
.
raw
);
formatted
=
std
::
move
(
other
.
formatted
);
other
.
clear
();
return
*
this
;
}
void
clear
()
{
level
=
level
::
off
;
raw
.
clear
();
formatted
.
clear
();
}
std
::
string
logger_name
;
level
::
level_enum
level
;
log_clock
::
time_point
time
;
size_t
thread_id
;
fmt
::
MemoryWriter
raw
;
fmt
::
MemoryWriter
formatted
;
};
}
}
include/spdlog/details/logger_impl.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/logger.h>
#include <memory>
#include <string>
// create logger with given name, sinks and the default pattern formatter
// all other ctors will call this one
template
<
class
It
>
inline
spdlog
::
logger
::
logger
(
const
std
::
string
&
logger_name
,
const
It
&
begin
,
const
It
&
end
)
:
_name
(
logger_name
),
_sinks
(
begin
,
end
),
_formatter
(
std
::
make_shared
<
pattern_formatter
>
(
"%+"
))
{
// no support under vs2013 for member initialization for std::atomic
_level
=
level
::
info
;
}
// ctor with sinks as init list
inline
spdlog
::
logger
::
logger
(
const
std
::
string
&
logger_name
,
sinks_init_list
sinks_list
)
:
logger
(
logger_name
,
sinks_list
.
begin
(),
sinks_list
.
end
())
{}
// ctor with single sink
inline
spdlog
::
logger
::
logger
(
const
std
::
string
&
logger_name
,
spdlog
::
sink_ptr
single_sink
)
:
logger
(
logger_name
,
{
single_sink
})
{}
inline
spdlog
::
logger
::~
logger
()
=
default
;
inline
void
spdlog
::
logger
::
set_formatter
(
spdlog
::
formatter_ptr
msg_formatter
)
{
_set_formatter
(
msg_formatter
);
}
inline
void
spdlog
::
logger
::
set_pattern
(
const
std
::
string
&
pattern
)
{
_set_pattern
(
pattern
);
}
//
// log only if given level>=logger's log level
//
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
_log_if_enabled
(
level
::
level_enum
lvl
,
const
char
*
fmt
,
const
Args
&
...
args
)
{
bool
msg_enabled
=
should_log
(
lvl
);
details
::
line_logger
l
(
this
,
lvl
,
msg_enabled
);
l
.
write
(
fmt
,
args
...);
return
l
;
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
_log_if_enabled
(
level
::
level_enum
lvl
)
{
return
details
::
line_logger
(
this
,
lvl
,
should_log
(
lvl
));
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
_log_if_enabled
(
level
::
level_enum
lvl
,
const
T
&
msg
)
{
bool
msg_enabled
=
should_log
(
lvl
);
details
::
line_logger
l
(
this
,
lvl
,
msg_enabled
);
l
<<
msg
;
return
l
;
}
//
// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
//
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
trace
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
trace
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
debug
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
debug
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
info
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
info
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
notice
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
notice
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
warn
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
warn
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
error
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
err
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
critical
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
critical
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
alert
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
alert
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
emerg
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
emerg
,
fmt
,
args
...);
}
//
// logger.info(msg) << ".." call style
//
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
trace
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
trace
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
debug
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
debug
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
info
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
info
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
notice
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
notice
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
warn
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
warn
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
error
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
err
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
critical
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
critical
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
alert
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
alert
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
emerg
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
emerg
,
msg
);
}
//
// logger.info() << ".." call style
//
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
trace
()
{
return
_log_if_enabled
(
level
::
trace
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
debug
()
{
return
_log_if_enabled
(
level
::
debug
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
info
()
{
return
_log_if_enabled
(
level
::
info
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
notice
()
{
return
_log_if_enabled
(
level
::
notice
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
warn
()
{
return
_log_if_enabled
(
level
::
warn
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
error
()
{
return
_log_if_enabled
(
level
::
err
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
critical
()
{
return
_log_if_enabled
(
level
::
critical
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
alert
()
{
return
_log_if_enabled
(
level
::
alert
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
emerg
()
{
return
_log_if_enabled
(
level
::
emerg
);
}
// always log, no matter what is the actual logger's log level
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
force_log
(
level
::
level_enum
lvl
,
const
char
*
fmt
,
const
Args
&
...
args
)
{
details
::
line_logger
l
(
this
,
lvl
,
true
);
l
.
write
(
fmt
,
args
...);
return
l
;
}
//
// name and level
//
inline
const
std
::
string
&
spdlog
::
logger
::
name
()
const
{
return
_name
;
}
inline
void
spdlog
::
logger
::
set_level
(
spdlog
::
level
::
level_enum
log_level
)
{
_level
.
store
(
log_level
);
}
inline
spdlog
::
level
::
level_enum
spdlog
::
logger
::
level
()
const
{
return
static_cast
<
spdlog
::
level
::
level_enum
>
(
_level
.
load
(
std
::
memory_order_relaxed
));
}
inline
bool
spdlog
::
logger
::
should_log
(
spdlog
::
level
::
level_enum
msg_level
)
const
{
return
msg_level
>=
_level
.
load
(
std
::
memory_order_relaxed
);
}
//
// protected virtual called at end of each user log call (if enabled) by the line_logger
//
inline
void
spdlog
::
logger
::
_log_msg
(
details
::
log_msg
&
msg
)
{
_formatter
->
format
(
msg
);
for
(
auto
&
sink
:
_sinks
)
sink
->
log
(
msg
);
}
inline
void
spdlog
::
logger
::
_set_pattern
(
const
std
::
string
&
pattern
)
{
_formatter
=
std
::
make_shared
<
pattern_formatter
>
(
pattern
);
}
inline
void
spdlog
::
logger
::
_set_formatter
(
formatter_ptr
msg_formatter
)
{
_formatter
=
msg_formatter
;
}
inline
void
spdlog
::
logger
::
flush
()
{
for
(
auto
&
sink
:
_sinks
)
sink
->
flush
();
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/logger.h>
#include <memory>
#include <string>
// create logger with given name, sinks and the default pattern formatter
// all other ctors will call this one
template
<
class
It
>
inline
spdlog
::
logger
::
logger
(
const
std
::
string
&
logger_name
,
const
It
&
begin
,
const
It
&
end
)
:
_name
(
logger_name
),
_sinks
(
begin
,
end
),
_formatter
(
std
::
make_shared
<
pattern_formatter
>
(
"%+"
))
{
// no support under vs2013 for member initialization for std::atomic
_level
=
level
::
info
;
}
// ctor with sinks as init list
inline
spdlog
::
logger
::
logger
(
const
std
::
string
&
logger_name
,
sinks_init_list
sinks_list
)
:
logger
(
logger_name
,
sinks_list
.
begin
(),
sinks_list
.
end
())
{}
// ctor with single sink
inline
spdlog
::
logger
::
logger
(
const
std
::
string
&
logger_name
,
spdlog
::
sink_ptr
single_sink
)
:
logger
(
logger_name
,
{
single_sink
})
{}
inline
spdlog
::
logger
::~
logger
()
=
default
;
inline
void
spdlog
::
logger
::
set_formatter
(
spdlog
::
formatter_ptr
msg_formatter
)
{
_set_formatter
(
msg_formatter
);
}
inline
void
spdlog
::
logger
::
set_pattern
(
const
std
::
string
&
pattern
)
{
_set_pattern
(
pattern
);
}
//
// log only if given level>=logger's log level
//
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
_log_if_enabled
(
level
::
level_enum
lvl
,
const
char
*
fmt
,
const
Args
&
...
args
)
{
bool
msg_enabled
=
should_log
(
lvl
);
details
::
line_logger
l
(
this
,
lvl
,
msg_enabled
);
l
.
write
(
fmt
,
args
...);
return
l
;
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
_log_if_enabled
(
level
::
level_enum
lvl
)
{
return
details
::
line_logger
(
this
,
lvl
,
should_log
(
lvl
));
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
_log_if_enabled
(
level
::
level_enum
lvl
,
const
T
&
msg
)
{
bool
msg_enabled
=
should_log
(
lvl
);
details
::
line_logger
l
(
this
,
lvl
,
msg_enabled
);
l
<<
msg
;
return
l
;
}
//
// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
//
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
trace
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
trace
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
debug
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
debug
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
info
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
info
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
notice
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
notice
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
warn
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
warn
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
error
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
err
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
critical
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
critical
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
alert
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
alert
,
fmt
,
args
...);
}
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
emerg
(
const
char
*
fmt
,
const
Args
&
...
args
)
{
return
_log_if_enabled
(
level
::
emerg
,
fmt
,
args
...);
}
//
// logger.info(msg) << ".." call style
//
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
trace
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
trace
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
debug
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
debug
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
info
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
info
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
notice
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
notice
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
warn
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
warn
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
error
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
err
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
critical
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
critical
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
alert
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
alert
,
msg
);
}
template
<
typename
T
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
emerg
(
const
T
&
msg
)
{
return
_log_if_enabled
(
level
::
emerg
,
msg
);
}
//
// logger.info() << ".." call style
//
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
trace
()
{
return
_log_if_enabled
(
level
::
trace
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
debug
()
{
return
_log_if_enabled
(
level
::
debug
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
info
()
{
return
_log_if_enabled
(
level
::
info
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
notice
()
{
return
_log_if_enabled
(
level
::
notice
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
warn
()
{
return
_log_if_enabled
(
level
::
warn
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
error
()
{
return
_log_if_enabled
(
level
::
err
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
critical
()
{
return
_log_if_enabled
(
level
::
critical
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
alert
()
{
return
_log_if_enabled
(
level
::
alert
);
}
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
emerg
()
{
return
_log_if_enabled
(
level
::
emerg
);
}
// always log, no matter what is the actual logger's log level
template
<
typename
...
Args
>
inline
spdlog
::
details
::
line_logger
spdlog
::
logger
::
force_log
(
level
::
level_enum
lvl
,
const
char
*
fmt
,
const
Args
&
...
args
)
{
details
::
line_logger
l
(
this
,
lvl
,
true
);
l
.
write
(
fmt
,
args
...);
return
l
;
}
//
// name and level
//
inline
const
std
::
string
&
spdlog
::
logger
::
name
()
const
{
return
_name
;
}
inline
void
spdlog
::
logger
::
set_level
(
spdlog
::
level
::
level_enum
log_level
)
{
_level
.
store
(
log_level
);
}
inline
spdlog
::
level
::
level_enum
spdlog
::
logger
::
level
()
const
{
return
static_cast
<
spdlog
::
level
::
level_enum
>
(
_level
.
load
(
std
::
memory_order_relaxed
));
}
inline
bool
spdlog
::
logger
::
should_log
(
spdlog
::
level
::
level_enum
msg_level
)
const
{
return
msg_level
>=
_level
.
load
(
std
::
memory_order_relaxed
);
}
//
// protected virtual called at end of each user log call (if enabled) by the line_logger
//
inline
void
spdlog
::
logger
::
_log_msg
(
details
::
log_msg
&
msg
)
{
_formatter
->
format
(
msg
);
for
(
auto
&
sink
:
_sinks
)
sink
->
log
(
msg
);
}
inline
void
spdlog
::
logger
::
_set_pattern
(
const
std
::
string
&
pattern
)
{
_formatter
=
std
::
make_shared
<
pattern_formatter
>
(
pattern
);
}
inline
void
spdlog
::
logger
::
_set_formatter
(
formatter_ptr
msg_formatter
)
{
_formatter
=
msg_formatter
;
}
inline
void
spdlog
::
logger
::
flush
()
{
for
(
auto
&
sink
:
_sinks
)
sink
->
flush
();
}
include/spdlog/details/mpmc_bounded_q.h
View file @
0d263598
/*
A modified version of Bounded MPMC queue by Dmitry Vyukov.
Original code from:
http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
licensed by Dmitry Vyukov under the terms below:
Simplified BSD license
Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the authors and
should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
*/
/*
The code in its current form adds the license below:
Copyright(c) 2015 Gabi Melman.
Distributed under the MIT License (http://opensource.org/licenses/MIT)
*/
#pragma once
#include <spdlog/common.h>
#include <atomic>
#include <utility>
namespace
spdlog
{
namespace
details
{
template
<
typename
T
>
class
mpmc_bounded_queue
{
public:
using
item_type
=
T
;
mpmc_bounded_queue
(
size_t
buffer_size
)
:
buffer_
(
new
cell_t
[
buffer_size
]),
buffer_mask_
(
buffer_size
-
1
)
{
//queue size must be power of two
if
(
!
((
buffer_size
>=
2
)
&&
((
buffer_size
&
(
buffer_size
-
1
))
==
0
)))
throw
spdlog_ex
(
"async logger queue size must be power of two"
);
for
(
size_t
i
=
0
;
i
!=
buffer_size
;
i
+=
1
)
buffer_
[
i
].
sequence_
.
store
(
i
,
std
::
memory_order_relaxed
);
enqueue_pos_
.
store
(
0
,
std
::
memory_order_relaxed
);
dequeue_pos_
.
store
(
0
,
std
::
memory_order_relaxed
);
}
~
mpmc_bounded_queue
()
{
delete
[]
buffer_
;
}
bool
enqueue
(
T
&&
data
)
{
cell_t
*
cell
;
size_t
pos
=
enqueue_pos_
.
load
(
std
::
memory_order_relaxed
);
for
(;;)
{
cell
=
&
buffer_
[
pos
&
buffer_mask_
];
size_t
seq
=
cell
->
sequence_
.
load
(
std
::
memory_order_acquire
);
intptr_t
dif
=
(
intptr_t
)
seq
-
(
intptr_t
)
pos
;
if
(
dif
==
0
)
{
if
(
enqueue_pos_
.
compare_exchange_weak
(
pos
,
pos
+
1
,
std
::
memory_order_relaxed
))
break
;
}
else
if
(
dif
<
0
)
{
return
false
;
}
else
{
pos
=
enqueue_pos_
.
load
(
std
::
memory_order_relaxed
);
}
}
cell
->
data_
=
std
::
move
(
data
);
cell
->
sequence_
.
store
(
pos
+
1
,
std
::
memory_order_release
);
return
true
;
}
bool
dequeue
(
T
&
data
)
{
cell_t
*
cell
;
size_t
pos
=
dequeue_pos_
.
load
(
std
::
memory_order_relaxed
);
for
(;;)
{
cell
=
&
buffer_
[
pos
&
buffer_mask_
];
size_t
seq
=
cell
->
sequence_
.
load
(
std
::
memory_order_acquire
);
intptr_t
dif
=
(
intptr_t
)
seq
-
(
intptr_t
)(
pos
+
1
);
if
(
dif
==
0
)
{
if
(
dequeue_pos_
.
compare_exchange_weak
(
pos
,
pos
+
1
,
std
::
memory_order_relaxed
))
break
;
}
else
if
(
dif
<
0
)
return
false
;
else
pos
=
dequeue_pos_
.
load
(
std
::
memory_order_relaxed
);
}
data
=
std
::
move
(
cell
->
data_
);
cell
->
sequence_
.
store
(
pos
+
buffer_mask_
+
1
,
std
::
memory_order_release
);
return
true
;
}
private:
struct
cell_t
{
std
::
atomic
<
size_t
>
sequence_
;
T
data_
;
};
static
size_t
const
cacheline_size
=
64
;
typedef
char
cacheline_pad_t
[
cacheline_size
];
cacheline_pad_t
pad0_
;
cell_t
*
const
buffer_
;
size_t
const
buffer_mask_
;
cacheline_pad_t
pad1_
;
std
::
atomic
<
size_t
>
enqueue_pos_
;
cacheline_pad_t
pad2_
;
std
::
atomic
<
size_t
>
dequeue_pos_
;
cacheline_pad_t
pad3_
;
mpmc_bounded_queue
(
mpmc_bounded_queue
const
&
);
void
operator
=
(
mpmc_bounded_queue
const
&
);
};
}
// ns details
}
// ns spdlog
/*
A modified version of Bounded MPMC queue by Dmitry Vyukov.
Original code from:
http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue
licensed by Dmitry Vyukov under the terms below:
Simplified BSD license
Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those of the authors and
should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov.
*/
/*
The code in its current form adds the license below:
Copyright(c) 2015 Gabi Melman.
Distributed under the MIT License (http://opensource.org/licenses/MIT)
*/
#pragma once
#include <spdlog/common.h>
#include <atomic>
#include <utility>
namespace
spdlog
{
namespace
details
{
template
<
typename
T
>
class
mpmc_bounded_queue
{
public:
using
item_type
=
T
;
mpmc_bounded_queue
(
size_t
buffer_size
)
:
buffer_
(
new
cell_t
[
buffer_size
]),
buffer_mask_
(
buffer_size
-
1
)
{
//queue size must be power of two
if
(
!
((
buffer_size
>=
2
)
&&
((
buffer_size
&
(
buffer_size
-
1
))
==
0
)))
throw
spdlog_ex
(
"async logger queue size must be power of two"
);
for
(
size_t
i
=
0
;
i
!=
buffer_size
;
i
+=
1
)
buffer_
[
i
].
sequence_
.
store
(
i
,
std
::
memory_order_relaxed
);
enqueue_pos_
.
store
(
0
,
std
::
memory_order_relaxed
);
dequeue_pos_
.
store
(
0
,
std
::
memory_order_relaxed
);
}
~
mpmc_bounded_queue
()
{
delete
[]
buffer_
;
}
bool
enqueue
(
T
&&
data
)
{
cell_t
*
cell
;
size_t
pos
=
enqueue_pos_
.
load
(
std
::
memory_order_relaxed
);
for
(;;)
{
cell
=
&
buffer_
[
pos
&
buffer_mask_
];
size_t
seq
=
cell
->
sequence_
.
load
(
std
::
memory_order_acquire
);
intptr_t
dif
=
(
intptr_t
)
seq
-
(
intptr_t
)
pos
;
if
(
dif
==
0
)
{
if
(
enqueue_pos_
.
compare_exchange_weak
(
pos
,
pos
+
1
,
std
::
memory_order_relaxed
))
break
;
}
else
if
(
dif
<
0
)
{
return
false
;
}
else
{
pos
=
enqueue_pos_
.
load
(
std
::
memory_order_relaxed
);
}
}
cell
->
data_
=
std
::
move
(
data
);
cell
->
sequence_
.
store
(
pos
+
1
,
std
::
memory_order_release
);
return
true
;
}
bool
dequeue
(
T
&
data
)
{
cell_t
*
cell
;
size_t
pos
=
dequeue_pos_
.
load
(
std
::
memory_order_relaxed
);
for
(;;)
{
cell
=
&
buffer_
[
pos
&
buffer_mask_
];
size_t
seq
=
cell
->
sequence_
.
load
(
std
::
memory_order_acquire
);
intptr_t
dif
=
(
intptr_t
)
seq
-
(
intptr_t
)(
pos
+
1
);
if
(
dif
==
0
)
{
if
(
dequeue_pos_
.
compare_exchange_weak
(
pos
,
pos
+
1
,
std
::
memory_order_relaxed
))
break
;
}
else
if
(
dif
<
0
)
return
false
;
else
pos
=
dequeue_pos_
.
load
(
std
::
memory_order_relaxed
);
}
data
=
std
::
move
(
cell
->
data_
);
cell
->
sequence_
.
store
(
pos
+
buffer_mask_
+
1
,
std
::
memory_order_release
);
return
true
;
}
private:
struct
cell_t
{
std
::
atomic
<
size_t
>
sequence_
;
T
data_
;
};
static
size_t
const
cacheline_size
=
64
;
typedef
char
cacheline_pad_t
[
cacheline_size
];
cacheline_pad_t
pad0_
;
cell_t
*
const
buffer_
;
size_t
const
buffer_mask_
;
cacheline_pad_t
pad1_
;
std
::
atomic
<
size_t
>
enqueue_pos_
;
cacheline_pad_t
pad2_
;
std
::
atomic
<
size_t
>
dequeue_pos_
;
cacheline_pad_t
pad3_
;
mpmc_bounded_queue
(
mpmc_bounded_queue
const
&
);
void
operator
=
(
mpmc_bounded_queue
const
&
);
};
}
// ns details
}
// ns spdlog
include/spdlog/details/null_mutex.h
View file @
0d263598
...
...
@@ -24,21 +24,21 @@ struct null_mutex
struct
null_atomic_int
{
int
value
;
null_atomic_int
()
=
default
;
int
value
;
null_atomic_int
()
=
default
;
null_atomic_int
(
int
val
)
:
value
(
val
)
{}
null_atomic_int
(
int
val
)
:
value
(
val
)
{}
int
load
(
std
::
memory_order
)
const
{
return
value
;
}
int
load
(
std
::
memory_order
)
const
{
return
value
;
}
void
store
(
int
val
)
{
value
=
val
;
}
void
store
(
int
val
)
{
value
=
val
;
}
};
}
...
...
include/spdlog/details/os.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/common.h>
#include <cstdio>
#include <ctime>
#include <functional>
#include <string>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX //prevent windows redefining min/max
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#ifdef __MINGW32__
#include <share.h>
#endif
#elif __linux__
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
#include <sys/stat.h>
#include <unistd.h>
#include <chrono>
#else
#include <thread>
#endif
namespace
spdlog
{
namespace
details
{
namespace
os
{
inline
spdlog
::
log_clock
::
time_point
now
()
{
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
timespec
ts
;
::
clock_gettime
(
CLOCK_REALTIME_COARSE
,
&
ts
);
return
std
::
chrono
::
time_point
<
log_clock
,
typename
log_clock
::
duration
>
(
std
::
chrono
::
duration_cast
<
typename
log_clock
::
duration
>
(
std
::
chrono
::
seconds
(
ts
.
tv_sec
)
+
std
::
chrono
::
nanoseconds
(
ts
.
tv_nsec
)));
#else
return
log_clock
::
now
();
#endif
}
inline
std
::
tm
localtime
(
const
std
::
time_t
&
time_tt
)
{
#ifdef _WIN32
std
::
tm
tm
;
localtime_s
(
&
tm
,
&
time_tt
);
#else
std
::
tm
tm
;
localtime_r
(
&
time_tt
,
&
tm
);
#endif
return
tm
;
}
inline
std
::
tm
localtime
()
{
std
::
time_t
now_t
=
time
(
nullptr
);
return
localtime
(
now_t
);
}
inline
std
::
tm
gmtime
(
const
std
::
time_t
&
time_tt
)
{
#ifdef _WIN32
std
::
tm
tm
;
gmtime_s
(
&
tm
,
&
time_tt
);
#else
std
::
tm
tm
;
gmtime_r
(
&
time_tt
,
&
tm
);
#endif
return
tm
;
}
inline
std
::
tm
gmtime
()
{
std
::
time_t
now_t
=
time
(
nullptr
);
return
gmtime
(
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
);
}
#ifdef _WIN32
inline
const
char
*
eol
()
{
return
"
\r\n
"
;
}
#else
constexpr
inline
const
char
*
eol
()
{
return
"
\n
"
;
}
#endif
#ifdef _WIN32
inline
unsigned
short
eol_size
()
{
return
2
;
}
#else
constexpr
inline
unsigned
short
eol_size
()
{
return
1
;
}
#endif
//fopen_s on non windows for writing
inline
int
fopen_s
(
FILE
**
fp
,
const
filename_t
&
filename
,
const
filename_t
&
mode
)
{
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
*
fp
=
_wfsopen
((
filename
.
c_str
()),
mode
.
c_str
(),
_SH_DENYWR
);
#else
*
fp
=
_fsopen
((
filename
.
c_str
()),
mode
.
c_str
(),
_SH_DENYWR
);
#endif
return
*
fp
==
nullptr
;
#else
*
fp
=
fopen
((
filename
.
c_str
()),
mode
.
c_str
());
return
*
fp
==
nullptr
;
#endif
}
inline
int
remove
(
const
filename_t
&
filename
)
{
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return
_wremove
(
filename
.
c_str
());
#else
return
std
::
remove
(
filename
.
c_str
());
#endif
}
inline
int
rename
(
const
filename_t
&
filename1
,
const
filename_t
&
filename2
)
{
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return
_wrename
(
filename1
.
c_str
(),
filename2
.
c_str
());
#else
return
std
::
rename
(
filename1
.
c_str
(),
filename2
.
c_str
());
#endif
}
//Return if file exists
inline
bool
file_exists
(
const
filename_t
&
filename
)
{
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
auto
attribs
=
GetFileAttributesW
(
filename
.
c_str
());
#else
auto
attribs
=
GetFileAttributesA
(
filename
.
c_str
());
#endif
return
(
attribs
!=
INVALID_FILE_ATTRIBUTES
&&
!
(
attribs
&
FILE_ATTRIBUTE_DIRECTORY
));
#elif __linux__
struct
stat
buffer
;
return
(
stat
(
filename
.
c_str
(),
&
buffer
)
==
0
);
#else
auto
*
file
=
fopen
(
filename
.
c_str
(),
"r"
);
if
(
file
!=
nullptr
)
{
fclose
(
file
);
return
true
;
}
return
false
;
#endif
}
//Return utc offset in minutes or throw spdlog_ex on failure
inline
int
utc_minutes_offset
(
const
std
::
tm
&
tm
=
details
::
os
::
localtime
())
{
#ifdef _WIN32
#if _WIN32_WINNT < _WIN32_WINNT_WS08
TIME_ZONE_INFORMATION
tzinfo
;
auto
rv
=
GetTimeZoneInformation
(
&
tzinfo
);
#else
DYNAMIC_TIME_ZONE_INFORMATION
tzinfo
;
auto
rv
=
GetDynamicTimeZoneInformation
(
&
tzinfo
);
#endif
if
(
rv
==
TIME_ZONE_ID_INVALID
)
throw
spdlog
::
spdlog_ex
(
"Failed getting timezone info. Last error: "
+
GetLastError
());
int
offset
=
-
tzinfo
.
Bias
;
if
(
tm
.
tm_isdst
)
offset
-=
tzinfo
.
DaylightBias
;
else
offset
-=
tzinfo
.
StandardBias
;
return
offset
;
#else
return
static_cast
<
int
>
(
tm
.
tm_gmtoff
/
60
);
#endif
}
//Return current thread id as size_t
//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
inline
size_t
thread_id
()
{
#ifdef _WIN32
return
static_cast
<
size_t
>
(
::
GetCurrentThreadId
());
#elif __linux__
# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
# define SYS_gettid __NR_gettid
# endif
return
static_cast
<
size_t
>
(
syscall
(
SYS_gettid
));
#else //Default to standard C++11 (OSX and other Unix)
return
static_cast
<
size_t
>
(
std
::
hash
<
std
::
thread
::
id
>
()(
std
::
this_thread
::
get_id
()));
#endif
}
}
//os
}
//details
}
//spdlog
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/common.h>
#include <cstdio>
#include <ctime>
#include <functional>
#include <string>
#ifdef _WIN32
#ifndef NOMINMAX
#define NOMINMAX //prevent windows redefining min/max
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#ifdef __MINGW32__
#include <share.h>
#endif
#elif __linux__
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
#include <sys/stat.h>
#include <unistd.h>
#include <chrono>
#else
#include <thread>
#endif
namespace
spdlog
{
namespace
details
{
namespace
os
{
inline
spdlog
::
log_clock
::
time_point
now
()
{
#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
timespec
ts
;
::
clock_gettime
(
CLOCK_REALTIME_COARSE
,
&
ts
);
return
std
::
chrono
::
time_point
<
log_clock
,
typename
log_clock
::
duration
>
(
std
::
chrono
::
duration_cast
<
typename
log_clock
::
duration
>
(
std
::
chrono
::
seconds
(
ts
.
tv_sec
)
+
std
::
chrono
::
nanoseconds
(
ts
.
tv_nsec
)));
#else
return
log_clock
::
now
();
#endif
}
inline
std
::
tm
localtime
(
const
std
::
time_t
&
time_tt
)
{
#ifdef _WIN32
std
::
tm
tm
;
localtime_s
(
&
tm
,
&
time_tt
);
#else
std
::
tm
tm
;
localtime_r
(
&
time_tt
,
&
tm
);
#endif
return
tm
;
}
inline
std
::
tm
localtime
()
{
std
::
time_t
now_t
=
time
(
nullptr
);
return
localtime
(
now_t
);
}
inline
std
::
tm
gmtime
(
const
std
::
time_t
&
time_tt
)
{
#ifdef _WIN32
std
::
tm
tm
;
gmtime_s
(
&
tm
,
&
time_tt
);
#else
std
::
tm
tm
;
gmtime_r
(
&
time_tt
,
&
tm
);
#endif
return
tm
;
}
inline
std
::
tm
gmtime
()
{
std
::
time_t
now_t
=
time
(
nullptr
);
return
gmtime
(
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
);
}
#ifdef _WIN32
inline
const
char
*
eol
()
{
return
"
\r\n
"
;
}
#else
constexpr
inline
const
char
*
eol
()
{
return
"
\n
"
;
}
#endif
#ifdef _WIN32
inline
unsigned
short
eol_size
()
{
return
2
;
}
#else
constexpr
inline
unsigned
short
eol_size
()
{
return
1
;
}
#endif
//fopen_s on non windows for writing
inline
int
fopen_s
(
FILE
**
fp
,
const
filename_t
&
filename
,
const
filename_t
&
mode
)
{
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
*
fp
=
_wfsopen
((
filename
.
c_str
()),
mode
.
c_str
(),
_SH_DENYWR
);
#else
*
fp
=
_fsopen
((
filename
.
c_str
()),
mode
.
c_str
(),
_SH_DENYWR
);
#endif
return
*
fp
==
nullptr
;
#else
*
fp
=
fopen
((
filename
.
c_str
()),
mode
.
c_str
());
return
*
fp
==
nullptr
;
#endif
}
inline
int
remove
(
const
filename_t
&
filename
)
{
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return
_wremove
(
filename
.
c_str
());
#else
return
std
::
remove
(
filename
.
c_str
());
#endif
}
inline
int
rename
(
const
filename_t
&
filename1
,
const
filename_t
&
filename2
)
{
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
return
_wrename
(
filename1
.
c_str
(),
filename2
.
c_str
());
#else
return
std
::
rename
(
filename1
.
c_str
(),
filename2
.
c_str
());
#endif
}
//Return if file exists
inline
bool
file_exists
(
const
filename_t
&
filename
)
{
#ifdef _WIN32
#ifdef SPDLOG_WCHAR_FILENAMES
auto
attribs
=
GetFileAttributesW
(
filename
.
c_str
());
#else
auto
attribs
=
GetFileAttributesA
(
filename
.
c_str
());
#endif
return
(
attribs
!=
INVALID_FILE_ATTRIBUTES
&&
!
(
attribs
&
FILE_ATTRIBUTE_DIRECTORY
));
#elif __linux__
struct
stat
buffer
;
return
(
stat
(
filename
.
c_str
(),
&
buffer
)
==
0
);
#else
auto
*
file
=
fopen
(
filename
.
c_str
(),
"r"
);
if
(
file
!=
nullptr
)
{
fclose
(
file
);
return
true
;
}
return
false
;
#endif
}
//Return utc offset in minutes or throw spdlog_ex on failure
inline
int
utc_minutes_offset
(
const
std
::
tm
&
tm
=
details
::
os
::
localtime
())
{
#ifdef _WIN32
#if _WIN32_WINNT < _WIN32_WINNT_WS08
TIME_ZONE_INFORMATION
tzinfo
;
auto
rv
=
GetTimeZoneInformation
(
&
tzinfo
);
#else
DYNAMIC_TIME_ZONE_INFORMATION
tzinfo
;
auto
rv
=
GetDynamicTimeZoneInformation
(
&
tzinfo
);
#endif
if
(
rv
==
TIME_ZONE_ID_INVALID
)
throw
spdlog
::
spdlog_ex
(
"Failed getting timezone info. Last error: "
+
GetLastError
());
int
offset
=
-
tzinfo
.
Bias
;
if
(
tm
.
tm_isdst
)
offset
-=
tzinfo
.
DaylightBias
;
else
offset
-=
tzinfo
.
StandardBias
;
return
offset
;
#else
return
static_cast
<
int
>
(
tm
.
tm_gmtoff
/
60
);
#endif
}
//Return current thread id as size_t
//It exists because the std::this_thread::get_id() is much slower(espcially under VS 2013)
inline
size_t
thread_id
()
{
#ifdef _WIN32
return
static_cast
<
size_t
>
(
::
GetCurrentThreadId
());
#elif __linux__
# if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
# define SYS_gettid __NR_gettid
# endif
return
static_cast
<
size_t
>
(
syscall
(
SYS_gettid
));
#else //Default to standard C++11 (OSX and other Unix)
return
static_cast
<
size_t
>
(
std
::
hash
<
std
::
thread
::
id
>
()(
std
::
this_thread
::
get_id
()));
#endif
}
}
//os
}
//details
}
//spdlog
include/spdlog/details/pattern_formatter_impl.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/formatter.h>
#include <spdlog/details/log_msg.h>
#include <spdlog/details/os.h>
#include <spdlog/details/format.h>
#include <chrono>
#include <ctime>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <utility>
#include <vector>
namespace
spdlog
{
namespace
details
{
class
flag_formatter
{
public:
virtual
~
flag_formatter
()
{}
virtual
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
=
0
;
};
///////////////////////////////////////////////////////////////////////
// name & level pattern appenders
///////////////////////////////////////////////////////////////////////
namespace
{
class
name_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
msg
.
logger_name
;
}
};
}
// log level appender
class
level_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
level
::
to_str
(
msg
.
level
);
}
};
// short log level appender
class
short_level_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
level
::
to_short_str
(
msg
.
level
);
}
};
///////////////////////////////////////////////////////////////////////
// Date time pattern appenders
///////////////////////////////////////////////////////////////////////
static
const
char
*
ampm
(
const
tm
&
t
)
{
return
t
.
tm_hour
>=
12
?
"PM"
:
"AM"
;
}
static
int
to12h
(
const
tm
&
t
)
{
return
t
.
tm_hour
>
12
?
t
.
tm_hour
-
12
:
t
.
tm_hour
;
}
//Abbreviated weekday name
static
const
std
::
string
days
[]
{
"Sun"
,
"Mon"
,
"Tue"
,
"Wed"
,
"Thu"
,
"Fri"
,
"Sat"
};
class
a_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
days
[
tm_time
.
tm_wday
];
}
};
//Full weekday name
static
const
std
::
string
full_days
[]
{
"Sunday"
,
"Monday"
,
"Tuesday"
,
"Wednesday"
,
"Thursday"
,
"Friday"
,
"Saturday"
};
class
A_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
full_days
[
tm_time
.
tm_wday
];
}
};
//Abbreviated month
static
const
std
::
string
months
[]
{
"Jan"
,
"Feb"
,
"Mar"
,
"Apr"
,
"May"
,
"June"
,
"July"
,
"Aug"
,
"Sept"
,
"Oct"
,
"Nov"
,
"Dec"
};
class
b_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
months
[
tm_time
.
tm_mon
];
}
};
//Full month name
static
const
std
::
string
full_months
[]
{
"January"
,
"February"
,
"March"
,
"April"
,
"May"
,
"June"
,
"July"
,
"August"
,
"September"
,
"October"
,
"November"
,
"December"
};
class
B_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
full_months
[
tm_time
.
tm_mon
];
}
};
//write 2 ints seperated by sep with padding of 2
static
fmt
::
MemoryWriter
&
pad_n_join
(
fmt
::
MemoryWriter
&
w
,
int
v1
,
int
v2
,
char
sep
)
{
w
<<
fmt
::
pad
(
v1
,
2
,
'0'
)
<<
sep
<<
fmt
::
pad
(
v2
,
2
,
'0'
);
return
w
;
}
//write 3 ints seperated by sep with padding of 2
static
fmt
::
MemoryWriter
&
pad_n_join
(
fmt
::
MemoryWriter
&
w
,
int
v1
,
int
v2
,
int
v3
,
char
sep
)
{
w
<<
fmt
::
pad
(
v1
,
2
,
'0'
)
<<
sep
<<
fmt
::
pad
(
v2
,
2
,
'0'
)
<<
sep
<<
fmt
::
pad
(
v3
,
2
,
'0'
);
return
w
;
}
//Date and time representation (Thu Aug 23 15:35:46 2014)
class
c_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
days
[
tm_time
.
tm_wday
]
<<
' '
<<
months
[
tm_time
.
tm_mon
]
<<
' '
<<
tm_time
.
tm_mday
<<
' '
;
pad_n_join
(
msg
.
formatted
,
tm_time
.
tm_hour
,
tm_time
.
tm_min
,
tm_time
.
tm_sec
,
':'
)
<<
' '
<<
tm_time
.
tm_year
+
1900
;
}
};
// year - 2 digit
class
C_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
tm_time
.
tm_year
%
100
,
2
,
'0'
);
}
};
// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01
class
D_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
pad_n_join
(
msg
.
formatted
,
tm_time
.
tm_mon
+
1
,
tm_time
.
tm_mday
,
tm_time
.
tm_year
%
100
,
'/'
);
}
};
// year - 4 digit
class
Y_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
tm_time
.
tm_year
+
1900
;
}
};
// month 1-12
class
m_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
tm_time
.
tm_mon
+
1
,
2
,
'0'
);
}
};
// day of month 1-31
class
d_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
tm_time
.
tm_mday
,
2
,
'0'
);
}
};
// hours in 24 format 0-23
class
H_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
tm_time
.
tm_hour
,
2
,
'0'
);
}
};
// hours in 12 format 1-12
class
I_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
to12h
(
tm_time
),
2
,
'0'
);
}
};
// minutes 0-59
class
M_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
tm_time
.
tm_min
,
2
,
'0'
);
}
};
// seconds 0-59
class
S_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
tm_time
.
tm_sec
,
2
,
'0'
);
}
};
// milliseconds
class
e_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
auto
duration
=
msg
.
time
.
time_since_epoch
();
auto
millis
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
milliseconds
>
(
duration
).
count
()
%
1000
;
msg
.
formatted
<<
fmt
::
pad
(
static_cast
<
int
>
(
millis
),
3
,
'0'
);
}
};
// microseconds
class
f_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
auto
duration
=
msg
.
time
.
time_since_epoch
();
auto
micros
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
microseconds
>
(
duration
).
count
()
%
1000000
;
msg
.
formatted
<<
fmt
::
pad
(
static_cast
<
int
>
(
micros
),
6
,
'0'
);
}
};
// nanoseconds
class
F_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
auto
duration
=
msg
.
time
.
time_since_epoch
();
auto
ns
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
nanoseconds
>
(
duration
).
count
()
%
1000000000
;
msg
.
formatted
<<
fmt
::
pad
(
static_cast
<
int
>
(
ns
),
9
,
'0'
);
}
};
// AM/PM
class
p_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
ampm
(
tm_time
);
}
};
// 12 hour clock 02:55:02 pm
class
r_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
pad_n_join
(
msg
.
formatted
,
to12h
(
tm_time
),
tm_time
.
tm_min
,
tm_time
.
tm_sec
,
':'
)
<<
' '
<<
ampm
(
tm_time
);
}
};
// 24-hour HH:MM time, equivalent to %H:%M
class
R_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
pad_n_join
(
msg
.
formatted
,
tm_time
.
tm_hour
,
tm_time
.
tm_min
,
':'
);
}
};
// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
class
T_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
pad_n_join
(
msg
.
formatted
,
tm_time
.
tm_hour
,
tm_time
.
tm_min
,
tm_time
.
tm_sec
,
':'
);
}
};
// ISO 8601 offset from UTC in timezone (+-HH:MM)
class
z_formatter
:
public
flag_formatter
{
public:
const
std
::
chrono
::
seconds
cache_refresh
=
std
::
chrono
::
seconds
(
5
);
z_formatter
()
:
_last_update
(
std
::
chrono
::
seconds
(
0
))
{}
z_formatter
(
const
z_formatter
&
)
=
delete
;
z_formatter
&
operator
=
(
const
z_formatter
&
)
=
delete
;
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
#ifdef _WIN32
int
total_minutes
=
get_cached_offset
(
msg
,
tm_time
);
#else
// No need to chache under gcc,
// it is very fast (already stored in tm.tm_gmtoff)
int
total_minutes
=
os
::
utc_minutes_offset
(
tm_time
);
#endif
int
h
=
total_minutes
/
60
;
int
m
=
total_minutes
%
60
;
if
(
h
>=
0
)
//minus sign will be printed anyway if negative
{
msg
.
formatted
<<
'+'
;
}
pad_n_join
(
msg
.
formatted
,
h
,
m
,
':'
);
}
private:
log_clock
::
time_point
_last_update
;
int
_offset_minutes
;
std
::
mutex
_mutex
;
int
get_cached_offset
(
const
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
{
using
namespace
std
::
chrono
;
std
::
lock_guard
<
std
::
mutex
>
l
(
_mutex
);
if
(
msg
.
time
-
_last_update
>=
cache_refresh
)
{
_offset_minutes
=
os
::
utc_minutes_offset
(
tm_time
);
_last_update
=
msg
.
time
;
}
return
_offset_minutes
;
}
};
//Thread id
class
t_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
msg
.
thread_id
;
}
};
class
v_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
fmt
::
StringRef
(
msg
.
raw
.
data
(),
msg
.
raw
.
size
());
}
};
class
ch_formatter
:
public
flag_formatter
{
public:
explicit
ch_formatter
(
char
ch
)
:
_ch
(
ch
)
{}
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
_ch
;
}
private:
char
_ch
;
};
//aggregate user chars to display as is
class
aggregate_formatter
:
public
flag_formatter
{
public:
aggregate_formatter
()
{}
void
add_ch
(
char
ch
)
{
_str
+=
ch
;
}
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
_str
;
}
private:
std
::
string
_str
;
};
// Full info formatter
// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
class
full_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
#ifndef SPDLOG_NO_DATETIME
auto
duration
=
msg
.
time
.
time_since_epoch
();
auto
millis
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
milliseconds
>
(
duration
).
count
()
%
1000
;
/* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads),
msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ",
tm_time.tm_year + 1900,
tm_time.tm_mon + 1,
tm_time.tm_mday,
tm_time.tm_hour,
tm_time.tm_min,
tm_time.tm_sec,
static_cast<int>(millis),
msg.logger_name,
level::to_str(msg.level),
msg.raw.str());*/
// Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads)
msg
.
formatted
<<
'['
<<
static_cast
<
unsigned
int
>
(
tm_time
.
tm_year
+
1900
)
<<
'-'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
tm_time
.
tm_mon
+
1
),
2
,
'0'
)
<<
'-'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
tm_time
.
tm_mday
),
2
,
'0'
)
<<
' '
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
tm_time
.
tm_hour
),
2
,
'0'
)
<<
':'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
tm_time
.
tm_min
),
2
,
'0'
)
<<
':'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
tm_time
.
tm_sec
),
2
,
'0'
)
<<
'.'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
millis
),
3
,
'0'
)
<<
"] "
;
//no datetime needed
#else
(
void
)
tm_time
;
#endif
#ifndef SPDLOG_NO_NAME
msg
.
formatted
<<
'['
<<
msg
.
logger_name
<<
"] "
;
#endif
msg
.
formatted
<<
'['
<<
level
::
to_str
(
msg
.
level
)
<<
"] "
;
msg
.
formatted
<<
fmt
::
StringRef
(
msg
.
raw
.
data
(),
msg
.
raw
.
size
());
}
};
}
}
///////////////////////////////////////////////////////////////////////////////
// pattern_formatter inline impl
///////////////////////////////////////////////////////////////////////////////
inline
spdlog
::
pattern_formatter
::
pattern_formatter
(
const
std
::
string
&
pattern
)
{
compile_pattern
(
pattern
);
}
inline
void
spdlog
::
pattern_formatter
::
compile_pattern
(
const
std
::
string
&
pattern
)
{
auto
end
=
pattern
.
end
();
std
::
unique_ptr
<
details
::
aggregate_formatter
>
user_chars
;
for
(
auto
it
=
pattern
.
begin
();
it
!=
end
;
++
it
)
{
if
(
*
it
==
'%'
)
{
if
(
user_chars
)
//append user chars found so far
_formatters
.
push_back
(
std
::
move
(
user_chars
));
if
(
++
it
!=
end
)
handle_flag
(
*
it
);
else
break
;
}
else
// chars not following the % sign should be displayed as is
{
if
(
!
user_chars
)
user_chars
=
std
::
unique_ptr
<
details
::
aggregate_formatter
>
(
new
details
::
aggregate_formatter
());
user_chars
->
add_ch
(
*
it
);
}
}
if
(
user_chars
)
//append raw chars found so far
{
_formatters
.
push_back
(
std
::
move
(
user_chars
));
}
}
inline
void
spdlog
::
pattern_formatter
::
handle_flag
(
char
flag
)
{
switch
(
flag
)
{
// logger name
case
'n'
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
name_formatter
()));
break
;
case
'l'
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
level_formatter
()));
break
;
case
'L'
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
short_level_formatter
()));
break
;
case
(
't'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
t_formatter
()));
break
;
case
(
'v'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
v_formatter
()));
break
;
case
(
'a'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
a_formatter
()));
break
;
case
(
'A'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
A_formatter
()));
break
;
case
(
'b'
)
:
case
(
'h'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
b_formatter
()));
break
;
case
(
'B'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
B_formatter
()));
break
;
case
(
'c'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
c_formatter
()));
break
;
case
(
'C'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
C_formatter
()));
break
;
case
(
'Y'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
Y_formatter
()));
break
;
case
(
'D'
)
:
case
(
'x'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
D_formatter
()));
break
;
case
(
'm'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
m_formatter
()));
break
;
case
(
'd'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
d_formatter
()));
break
;
case
(
'H'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
H_formatter
()));
break
;
case
(
'I'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
I_formatter
()));
break
;
case
(
'M'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
M_formatter
()));
break
;
case
(
'S'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
S_formatter
()));
break
;
case
(
'e'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
e_formatter
()));
break
;
case
(
'f'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
f_formatter
()));
break
;
case
(
'F'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
F_formatter
()));
break
;
case
(
'p'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
p_formatter
()));
break
;
case
(
'r'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
r_formatter
()));
break
;
case
(
'R'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
R_formatter
()));
break
;
case
(
'T'
)
:
case
(
'X'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
T_formatter
()));
break
;
case
(
'z'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
z_formatter
()));
break
;
case
(
'+'
):
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
full_formatter
()));
break
;
default:
//Unkown flag appears as is
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
ch_formatter
(
'%'
)));
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
ch_formatter
(
flag
)));
break
;
}
}
inline
void
spdlog
::
pattern_formatter
::
format
(
details
::
log_msg
&
msg
)
{
try
{
auto
tm_time
=
details
::
os
::
localtime
(
log_clock
::
to_time_t
(
msg
.
time
));
for
(
auto
&
f
:
_formatters
)
{
f
->
format
(
msg
,
tm_time
);
}
//write eol
msg
.
formatted
<<
details
::
os
::
eol
();
}
catch
(
const
fmt
::
FormatError
&
e
)
{
throw
spdlog_ex
(
fmt
::
format
(
"formatting error while processing format string: {}"
,
e
.
what
()));
}
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/formatter.h>
#include <spdlog/details/log_msg.h>
#include <spdlog/details/os.h>
#include <spdlog/details/format.h>
#include <chrono>
#include <ctime>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <utility>
#include <vector>
namespace
spdlog
{
namespace
details
{
class
flag_formatter
{
public:
virtual
~
flag_formatter
()
{}
virtual
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
=
0
;
};
///////////////////////////////////////////////////////////////////////
// name & level pattern appenders
///////////////////////////////////////////////////////////////////////
namespace
{
class
name_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
msg
.
logger_name
;
}
};
}
// log level appender
class
level_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
level
::
to_str
(
msg
.
level
);
}
};
// short log level appender
class
short_level_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
level
::
to_short_str
(
msg
.
level
);
}
};
///////////////////////////////////////////////////////////////////////
// Date time pattern appenders
///////////////////////////////////////////////////////////////////////
static
const
char
*
ampm
(
const
tm
&
t
)
{
return
t
.
tm_hour
>=
12
?
"PM"
:
"AM"
;
}
static
int
to12h
(
const
tm
&
t
)
{
return
t
.
tm_hour
>
12
?
t
.
tm_hour
-
12
:
t
.
tm_hour
;
}
//Abbreviated weekday name
static
const
std
::
string
days
[]
{
"Sun"
,
"Mon"
,
"Tue"
,
"Wed"
,
"Thu"
,
"Fri"
,
"Sat"
};
class
a_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
days
[
tm_time
.
tm_wday
];
}
};
//Full weekday name
static
const
std
::
string
full_days
[]
{
"Sunday"
,
"Monday"
,
"Tuesday"
,
"Wednesday"
,
"Thursday"
,
"Friday"
,
"Saturday"
};
class
A_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
full_days
[
tm_time
.
tm_wday
];
}
};
//Abbreviated month
static
const
std
::
string
months
[]
{
"Jan"
,
"Feb"
,
"Mar"
,
"Apr"
,
"May"
,
"June"
,
"July"
,
"Aug"
,
"Sept"
,
"Oct"
,
"Nov"
,
"Dec"
};
class
b_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
months
[
tm_time
.
tm_mon
];
}
};
//Full month name
static
const
std
::
string
full_months
[]
{
"January"
,
"February"
,
"March"
,
"April"
,
"May"
,
"June"
,
"July"
,
"August"
,
"September"
,
"October"
,
"November"
,
"December"
};
class
B_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
full_months
[
tm_time
.
tm_mon
];
}
};
//write 2 ints seperated by sep with padding of 2
static
fmt
::
MemoryWriter
&
pad_n_join
(
fmt
::
MemoryWriter
&
w
,
int
v1
,
int
v2
,
char
sep
)
{
w
<<
fmt
::
pad
(
v1
,
2
,
'0'
)
<<
sep
<<
fmt
::
pad
(
v2
,
2
,
'0'
);
return
w
;
}
//write 3 ints seperated by sep with padding of 2
static
fmt
::
MemoryWriter
&
pad_n_join
(
fmt
::
MemoryWriter
&
w
,
int
v1
,
int
v2
,
int
v3
,
char
sep
)
{
w
<<
fmt
::
pad
(
v1
,
2
,
'0'
)
<<
sep
<<
fmt
::
pad
(
v2
,
2
,
'0'
)
<<
sep
<<
fmt
::
pad
(
v3
,
2
,
'0'
);
return
w
;
}
//Date and time representation (Thu Aug 23 15:35:46 2014)
class
c_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
days
[
tm_time
.
tm_wday
]
<<
' '
<<
months
[
tm_time
.
tm_mon
]
<<
' '
<<
tm_time
.
tm_mday
<<
' '
;
pad_n_join
(
msg
.
formatted
,
tm_time
.
tm_hour
,
tm_time
.
tm_min
,
tm_time
.
tm_sec
,
':'
)
<<
' '
<<
tm_time
.
tm_year
+
1900
;
}
};
// year - 2 digit
class
C_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
tm_time
.
tm_year
%
100
,
2
,
'0'
);
}
};
// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01
class
D_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
pad_n_join
(
msg
.
formatted
,
tm_time
.
tm_mon
+
1
,
tm_time
.
tm_mday
,
tm_time
.
tm_year
%
100
,
'/'
);
}
};
// year - 4 digit
class
Y_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
tm_time
.
tm_year
+
1900
;
}
};
// month 1-12
class
m_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
tm_time
.
tm_mon
+
1
,
2
,
'0'
);
}
};
// day of month 1-31
class
d_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
tm_time
.
tm_mday
,
2
,
'0'
);
}
};
// hours in 24 format 0-23
class
H_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
tm_time
.
tm_hour
,
2
,
'0'
);
}
};
// hours in 12 format 1-12
class
I_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
to12h
(
tm_time
),
2
,
'0'
);
}
};
// minutes 0-59
class
M_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
tm_time
.
tm_min
,
2
,
'0'
);
}
};
// seconds 0-59
class
S_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
fmt
::
pad
(
tm_time
.
tm_sec
,
2
,
'0'
);
}
};
// milliseconds
class
e_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
auto
duration
=
msg
.
time
.
time_since_epoch
();
auto
millis
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
milliseconds
>
(
duration
).
count
()
%
1000
;
msg
.
formatted
<<
fmt
::
pad
(
static_cast
<
int
>
(
millis
),
3
,
'0'
);
}
};
// microseconds
class
f_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
auto
duration
=
msg
.
time
.
time_since_epoch
();
auto
micros
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
microseconds
>
(
duration
).
count
()
%
1000000
;
msg
.
formatted
<<
fmt
::
pad
(
static_cast
<
int
>
(
micros
),
6
,
'0'
);
}
};
// nanoseconds
class
F_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
auto
duration
=
msg
.
time
.
time_since_epoch
();
auto
ns
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
nanoseconds
>
(
duration
).
count
()
%
1000000000
;
msg
.
formatted
<<
fmt
::
pad
(
static_cast
<
int
>
(
ns
),
9
,
'0'
);
}
};
// AM/PM
class
p_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
msg
.
formatted
<<
ampm
(
tm_time
);
}
};
// 12 hour clock 02:55:02 pm
class
r_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
pad_n_join
(
msg
.
formatted
,
to12h
(
tm_time
),
tm_time
.
tm_min
,
tm_time
.
tm_sec
,
':'
)
<<
' '
<<
ampm
(
tm_time
);
}
};
// 24-hour HH:MM time, equivalent to %H:%M
class
R_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
pad_n_join
(
msg
.
formatted
,
tm_time
.
tm_hour
,
tm_time
.
tm_min
,
':'
);
}
};
// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
class
T_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
pad_n_join
(
msg
.
formatted
,
tm_time
.
tm_hour
,
tm_time
.
tm_min
,
tm_time
.
tm_sec
,
':'
);
}
};
// ISO 8601 offset from UTC in timezone (+-HH:MM)
class
z_formatter
:
public
flag_formatter
{
public:
const
std
::
chrono
::
seconds
cache_refresh
=
std
::
chrono
::
seconds
(
5
);
z_formatter
()
:
_last_update
(
std
::
chrono
::
seconds
(
0
))
{}
z_formatter
(
const
z_formatter
&
)
=
delete
;
z_formatter
&
operator
=
(
const
z_formatter
&
)
=
delete
;
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
#ifdef _WIN32
int
total_minutes
=
get_cached_offset
(
msg
,
tm_time
);
#else
// No need to chache under gcc,
// it is very fast (already stored in tm.tm_gmtoff)
int
total_minutes
=
os
::
utc_minutes_offset
(
tm_time
);
#endif
int
h
=
total_minutes
/
60
;
int
m
=
total_minutes
%
60
;
if
(
h
>=
0
)
//minus sign will be printed anyway if negative
{
msg
.
formatted
<<
'+'
;
}
pad_n_join
(
msg
.
formatted
,
h
,
m
,
':'
);
}
private:
log_clock
::
time_point
_last_update
;
int
_offset_minutes
;
std
::
mutex
_mutex
;
int
get_cached_offset
(
const
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
{
using
namespace
std
::
chrono
;
std
::
lock_guard
<
std
::
mutex
>
l
(
_mutex
);
if
(
msg
.
time
-
_last_update
>=
cache_refresh
)
{
_offset_minutes
=
os
::
utc_minutes_offset
(
tm_time
);
_last_update
=
msg
.
time
;
}
return
_offset_minutes
;
}
};
//Thread id
class
t_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
msg
.
thread_id
;
}
};
class
v_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
fmt
::
StringRef
(
msg
.
raw
.
data
(),
msg
.
raw
.
size
());
}
};
class
ch_formatter
:
public
flag_formatter
{
public:
explicit
ch_formatter
(
char
ch
)
:
_ch
(
ch
)
{}
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
_ch
;
}
private:
char
_ch
;
};
//aggregate user chars to display as is
class
aggregate_formatter
:
public
flag_formatter
{
public:
aggregate_formatter
()
{}
void
add_ch
(
char
ch
)
{
_str
+=
ch
;
}
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
)
override
{
msg
.
formatted
<<
_str
;
}
private:
std
::
string
_str
;
};
// Full info formatter
// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
class
full_formatter
:
public
flag_formatter
{
void
format
(
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
override
{
#ifndef SPDLOG_NO_DATETIME
auto
duration
=
msg
.
time
.
time_since_epoch
();
auto
millis
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
milliseconds
>
(
duration
).
count
()
%
1000
;
/* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads),
msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ",
tm_time.tm_year + 1900,
tm_time.tm_mon + 1,
tm_time.tm_mday,
tm_time.tm_hour,
tm_time.tm_min,
tm_time.tm_sec,
static_cast<int>(millis),
msg.logger_name,
level::to_str(msg.level),
msg.raw.str());*/
// Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads)
msg
.
formatted
<<
'['
<<
static_cast
<
unsigned
int
>
(
tm_time
.
tm_year
+
1900
)
<<
'-'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
tm_time
.
tm_mon
+
1
),
2
,
'0'
)
<<
'-'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
tm_time
.
tm_mday
),
2
,
'0'
)
<<
' '
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
tm_time
.
tm_hour
),
2
,
'0'
)
<<
':'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
tm_time
.
tm_min
),
2
,
'0'
)
<<
':'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
tm_time
.
tm_sec
),
2
,
'0'
)
<<
'.'
<<
fmt
::
pad
(
static_cast
<
unsigned
int
>
(
millis
),
3
,
'0'
)
<<
"] "
;
//no datetime needed
#else
(
void
)
tm_time
;
#endif
#ifndef SPDLOG_NO_NAME
msg
.
formatted
<<
'['
<<
msg
.
logger_name
<<
"] "
;
#endif
msg
.
formatted
<<
'['
<<
level
::
to_str
(
msg
.
level
)
<<
"] "
;
msg
.
formatted
<<
fmt
::
StringRef
(
msg
.
raw
.
data
(),
msg
.
raw
.
size
());
}
};
}
}
///////////////////////////////////////////////////////////////////////////////
// pattern_formatter inline impl
///////////////////////////////////////////////////////////////////////////////
inline
spdlog
::
pattern_formatter
::
pattern_formatter
(
const
std
::
string
&
pattern
)
{
compile_pattern
(
pattern
);
}
inline
void
spdlog
::
pattern_formatter
::
compile_pattern
(
const
std
::
string
&
pattern
)
{
auto
end
=
pattern
.
end
();
std
::
unique_ptr
<
details
::
aggregate_formatter
>
user_chars
;
for
(
auto
it
=
pattern
.
begin
();
it
!=
end
;
++
it
)
{
if
(
*
it
==
'%'
)
{
if
(
user_chars
)
//append user chars found so far
_formatters
.
push_back
(
std
::
move
(
user_chars
));
if
(
++
it
!=
end
)
handle_flag
(
*
it
);
else
break
;
}
else
// chars not following the % sign should be displayed as is
{
if
(
!
user_chars
)
user_chars
=
std
::
unique_ptr
<
details
::
aggregate_formatter
>
(
new
details
::
aggregate_formatter
());
user_chars
->
add_ch
(
*
it
);
}
}
if
(
user_chars
)
//append raw chars found so far
{
_formatters
.
push_back
(
std
::
move
(
user_chars
));
}
}
inline
void
spdlog
::
pattern_formatter
::
handle_flag
(
char
flag
)
{
switch
(
flag
)
{
// logger name
case
'n'
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
name_formatter
()));
break
;
case
'l'
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
level_formatter
()));
break
;
case
'L'
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
short_level_formatter
()));
break
;
case
(
't'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
t_formatter
()));
break
;
case
(
'v'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
v_formatter
()));
break
;
case
(
'a'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
a_formatter
()));
break
;
case
(
'A'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
A_formatter
()));
break
;
case
(
'b'
)
:
case
(
'h'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
b_formatter
()));
break
;
case
(
'B'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
B_formatter
()));
break
;
case
(
'c'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
c_formatter
()));
break
;
case
(
'C'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
C_formatter
()));
break
;
case
(
'Y'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
Y_formatter
()));
break
;
case
(
'D'
)
:
case
(
'x'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
D_formatter
()));
break
;
case
(
'm'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
m_formatter
()));
break
;
case
(
'd'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
d_formatter
()));
break
;
case
(
'H'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
H_formatter
()));
break
;
case
(
'I'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
I_formatter
()));
break
;
case
(
'M'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
M_formatter
()));
break
;
case
(
'S'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
S_formatter
()));
break
;
case
(
'e'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
e_formatter
()));
break
;
case
(
'f'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
f_formatter
()));
break
;
case
(
'F'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
F_formatter
()));
break
;
case
(
'p'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
p_formatter
()));
break
;
case
(
'r'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
r_formatter
()));
break
;
case
(
'R'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
R_formatter
()));
break
;
case
(
'T'
)
:
case
(
'X'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
T_formatter
()));
break
;
case
(
'z'
)
:
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
z_formatter
()));
break
;
case
(
'+'
):
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
full_formatter
()));
break
;
default:
//Unkown flag appears as is
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
ch_formatter
(
'%'
)));
_formatters
.
push_back
(
std
::
unique_ptr
<
details
::
flag_formatter
>
(
new
details
::
ch_formatter
(
flag
)));
break
;
}
}
inline
void
spdlog
::
pattern_formatter
::
format
(
details
::
log_msg
&
msg
)
{
try
{
auto
tm_time
=
details
::
os
::
localtime
(
log_clock
::
to_time_t
(
msg
.
time
));
for
(
auto
&
f
:
_formatters
)
{
f
->
format
(
msg
,
tm_time
);
}
//write eol
msg
.
formatted
<<
details
::
os
::
eol
();
}
catch
(
const
fmt
::
FormatError
&
e
)
{
throw
spdlog_ex
(
fmt
::
format
(
"formatting error while processing format string: {}"
,
e
.
what
()));
}
}
include/spdlog/details/registry.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Loggers registy of unique name->logger pointer
// An attempt to create a logger with an already existing name will be ignored
// If user requests a non existing logger, nullptr will be returned
// This class is thread safe
#include <spdlog/details/null_mutex.h>
#include <spdlog/logger.h>
#include <spdlog/async_logger.h>
#include <spdlog/common.h>
#include <chrono>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
namespace
spdlog
{
namespace
details
{
template
<
class
Mutex
>
class
registry_t
{
public:
void
register_logger
(
std
::
shared_ptr
<
logger
>
logger
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
auto
logger_name
=
logger
->
name
();
throw_if_exists
(
logger_name
);
_loggers
[
logger_name
]
=
logger
;
}
std
::
shared_ptr
<
logger
>
get
(
const
std
::
string
&
logger_name
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
auto
found
=
_loggers
.
find
(
logger_name
);
return
found
==
_loggers
.
end
()
?
nullptr
:
found
->
second
;
}
template
<
class
It
>
std
::
shared_ptr
<
logger
>
create
(
const
std
::
string
&
logger_name
,
const
It
&
sinks_begin
,
const
It
&
sinks_end
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
throw_if_exists
(
logger_name
);
std
::
shared_ptr
<
logger
>
new_logger
;
if
(
_async_mode
)
new_logger
=
std
::
make_shared
<
async_logger
>
(
logger_name
,
sinks_begin
,
sinks_end
,
_async_q_size
,
_overflow_policy
,
_worker_warmup_cb
,
_flush_interval_ms
);
else
new_logger
=
std
::
make_shared
<
logger
>
(
logger_name
,
sinks_begin
,
sinks_end
);
if
(
_formatter
)
new_logger
->
set_formatter
(
_formatter
);
new_logger
->
set_level
(
_level
);
//Add to registry
_loggers
[
logger_name
]
=
new_logger
;
return
new_logger
;
}
void
drop
(
const
std
::
string
&
logger_name
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_loggers
.
erase
(
logger_name
);
}
void
drop_all
()
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_loggers
.
clear
();
}
std
::
shared_ptr
<
logger
>
create
(
const
std
::
string
&
logger_name
,
sinks_init_list
sinks
)
{
return
create
(
logger_name
,
sinks
.
begin
(),
sinks
.
end
());
}
std
::
shared_ptr
<
logger
>
create
(
const
std
::
string
&
logger_name
,
sink_ptr
sink
)
{
return
create
(
logger_name
,
{
sink
});
}
void
formatter
(
formatter_ptr
f
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_formatter
=
f
;
for
(
auto
&
l
:
_loggers
)
l
.
second
->
set_formatter
(
_formatter
);
}
void
set_pattern
(
const
std
::
string
&
pattern
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_formatter
=
std
::
make_shared
<
pattern_formatter
>
(
pattern
);
for
(
auto
&
l
:
_loggers
)
l
.
second
->
set_formatter
(
_formatter
);
}
void
set_level
(
level
::
level_enum
log_level
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
for
(
auto
&
l
:
_loggers
)
l
.
second
->
set_level
(
log_level
);
_level
=
log_level
;
}
void
set_async_mode
(
size_t
q_size
,
const
async_overflow_policy
overflow_policy
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_async_mode
=
true
;
_async_q_size
=
q_size
;
_overflow_policy
=
overflow_policy
;
_worker_warmup_cb
=
worker_warmup_cb
;
_flush_interval_ms
=
flush_interval_ms
;
}
void
set_sync_mode
()
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_async_mode
=
false
;
}
static
registry_t
<
Mutex
>&
instance
()
{
static
registry_t
<
Mutex
>
s_instance
;
return
s_instance
;
}
private:
registry_t
<
Mutex
>
()
{}
registry_t
<
Mutex
>
(
const
registry_t
<
Mutex
>&
)
=
delete
;
registry_t
<
Mutex
>&
operator
=
(
const
registry_t
<
Mutex
>&
)
=
delete
;
void
throw_if_exists
(
const
std
::
string
&
logger_name
)
{
if
(
_loggers
.
find
(
logger_name
)
!=
_loggers
.
end
())
throw
spdlog_ex
(
"logger with name '"
+
logger_name
+
"' already exists"
);
}
Mutex
_mutex
;
std
::
unordered_map
<
std
::
string
,
std
::
shared_ptr
<
logger
>>
_loggers
;
formatter_ptr
_formatter
;
level
::
level_enum
_level
=
level
::
info
;
bool
_async_mode
=
false
;
size_t
_async_q_size
=
0
;
async_overflow_policy
_overflow_policy
=
async_overflow_policy
::
block_retry
;
std
::
function
<
void
()
>
_worker_warmup_cb
=
nullptr
;
std
::
chrono
::
milliseconds
_flush_interval_ms
;
};
#ifdef SPDLOG_NO_REGISTRY_MUTEX
typedef
registry_t
<
spdlog
::
details
::
null_mutex
>
registry
;
#else
typedef
registry_t
<
std
::
mutex
>
registry
;
#endif
}
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Loggers registy of unique name->logger pointer
// An attempt to create a logger with an already existing name will be ignored
// If user requests a non existing logger, nullptr will be returned
// This class is thread safe
#include <spdlog/details/null_mutex.h>
#include <spdlog/logger.h>
#include <spdlog/async_logger.h>
#include <spdlog/common.h>
#include <chrono>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
namespace
spdlog
{
namespace
details
{
template
<
class
Mutex
>
class
registry_t
{
public:
void
register_logger
(
std
::
shared_ptr
<
logger
>
logger
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
auto
logger_name
=
logger
->
name
();
throw_if_exists
(
logger_name
);
_loggers
[
logger_name
]
=
logger
;
}
std
::
shared_ptr
<
logger
>
get
(
const
std
::
string
&
logger_name
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
auto
found
=
_loggers
.
find
(
logger_name
);
return
found
==
_loggers
.
end
()
?
nullptr
:
found
->
second
;
}
template
<
class
It
>
std
::
shared_ptr
<
logger
>
create
(
const
std
::
string
&
logger_name
,
const
It
&
sinks_begin
,
const
It
&
sinks_end
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
throw_if_exists
(
logger_name
);
std
::
shared_ptr
<
logger
>
new_logger
;
if
(
_async_mode
)
new_logger
=
std
::
make_shared
<
async_logger
>
(
logger_name
,
sinks_begin
,
sinks_end
,
_async_q_size
,
_overflow_policy
,
_worker_warmup_cb
,
_flush_interval_ms
);
else
new_logger
=
std
::
make_shared
<
logger
>
(
logger_name
,
sinks_begin
,
sinks_end
);
if
(
_formatter
)
new_logger
->
set_formatter
(
_formatter
);
new_logger
->
set_level
(
_level
);
//Add to registry
_loggers
[
logger_name
]
=
new_logger
;
return
new_logger
;
}
void
drop
(
const
std
::
string
&
logger_name
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_loggers
.
erase
(
logger_name
);
}
void
drop_all
()
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_loggers
.
clear
();
}
std
::
shared_ptr
<
logger
>
create
(
const
std
::
string
&
logger_name
,
sinks_init_list
sinks
)
{
return
create
(
logger_name
,
sinks
.
begin
(),
sinks
.
end
());
}
std
::
shared_ptr
<
logger
>
create
(
const
std
::
string
&
logger_name
,
sink_ptr
sink
)
{
return
create
(
logger_name
,
{
sink
});
}
void
formatter
(
formatter_ptr
f
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_formatter
=
f
;
for
(
auto
&
l
:
_loggers
)
l
.
second
->
set_formatter
(
_formatter
);
}
void
set_pattern
(
const
std
::
string
&
pattern
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_formatter
=
std
::
make_shared
<
pattern_formatter
>
(
pattern
);
for
(
auto
&
l
:
_loggers
)
l
.
second
->
set_formatter
(
_formatter
);
}
void
set_level
(
level
::
level_enum
log_level
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
for
(
auto
&
l
:
_loggers
)
l
.
second
->
set_level
(
log_level
);
_level
=
log_level
;
}
void
set_async_mode
(
size_t
q_size
,
const
async_overflow_policy
overflow_policy
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
)
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_async_mode
=
true
;
_async_q_size
=
q_size
;
_overflow_policy
=
overflow_policy
;
_worker_warmup_cb
=
worker_warmup_cb
;
_flush_interval_ms
=
flush_interval_ms
;
}
void
set_sync_mode
()
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_async_mode
=
false
;
}
static
registry_t
<
Mutex
>&
instance
()
{
static
registry_t
<
Mutex
>
s_instance
;
return
s_instance
;
}
private:
registry_t
<
Mutex
>
()
{}
registry_t
<
Mutex
>
(
const
registry_t
<
Mutex
>&
)
=
delete
;
registry_t
<
Mutex
>&
operator
=
(
const
registry_t
<
Mutex
>&
)
=
delete
;
void
throw_if_exists
(
const
std
::
string
&
logger_name
)
{
if
(
_loggers
.
find
(
logger_name
)
!=
_loggers
.
end
())
throw
spdlog_ex
(
"logger with name '"
+
logger_name
+
"' already exists"
);
}
Mutex
_mutex
;
std
::
unordered_map
<
std
::
string
,
std
::
shared_ptr
<
logger
>>
_loggers
;
formatter_ptr
_formatter
;
level
::
level_enum
_level
=
level
::
info
;
bool
_async_mode
=
false
;
size_t
_async_q_size
=
0
;
async_overflow_policy
_overflow_policy
=
async_overflow_policy
::
block_retry
;
std
::
function
<
void
()
>
_worker_warmup_cb
=
nullptr
;
std
::
chrono
::
milliseconds
_flush_interval_ms
;
};
#ifdef SPDLOG_NO_REGISTRY_MUTEX
typedef
registry_t
<
spdlog
::
details
::
null_mutex
>
registry
;
#else
typedef
registry_t
<
std
::
mutex
>
registry
;
#endif
}
}
include/spdlog/details/spdlog_impl.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// Global registry functions
//
#include <spdlog/spdlog.h>
#include <spdlog/details/registry.h>
#include <spdlog/sinks/file_sinks.h>
#include <spdlog/sinks/stdout_sinks.h>
#include <spdlog/sinks/syslog_sink.h>
#include <spdlog/sinks/ansicolor_sink.h>
#include <chrono>
#include <functional>
#include <memory>
#include <string>
inline
void
spdlog
::
register_logger
(
std
::
shared_ptr
<
logger
>
logger
)
{
return
details
::
registry
::
instance
().
register_logger
(
logger
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
get
(
const
std
::
string
&
name
)
{
return
details
::
registry
::
instance
().
get
(
name
);
}
inline
void
spdlog
::
drop
(
const
std
::
string
&
name
)
{
details
::
registry
::
instance
().
drop
(
name
);
}
// Create multi/single threaded rotating file logger
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
rotating_logger_mt
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
size_t
max_file_size
,
size_t
max_files
,
bool
force_flush
)
{
return
create
<
spdlog
::
sinks
::
rotating_file_sink_mt
>
(
logger_name
,
filename
,
SPDLOG_FILENAME_T
(
"txt"
),
max_file_size
,
max_files
,
force_flush
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
rotating_logger_st
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
size_t
max_file_size
,
size_t
max_files
,
bool
force_flush
)
{
return
create
<
spdlog
::
sinks
::
rotating_file_sink_st
>
(
logger_name
,
filename
,
SPDLOG_FILENAME_T
(
"txt"
),
max_file_size
,
max_files
,
force_flush
);
}
// Create file logger which creates new file at midnight):
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
daily_logger_mt
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
int
hour
,
int
minute
,
bool
force_flush
)
{
return
create
<
spdlog
::
sinks
::
daily_file_sink_mt
>
(
logger_name
,
filename
,
SPDLOG_FILENAME_T
(
"txt"
),
hour
,
minute
,
force_flush
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
daily_logger_st
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
int
hour
,
int
minute
,
bool
force_flush
)
{
return
create
<
spdlog
::
sinks
::
daily_file_sink_st
>
(
logger_name
,
filename
,
SPDLOG_FILENAME_T
(
"txt"
),
hour
,
minute
,
force_flush
);
}
// Create stdout/stderr loggers (with optinal color support)
inline
std
::
shared_ptr
<
spdlog
::
logger
>
create_console_logger
(
const
std
::
string
&
logger_name
,
spdlog
::
sink_ptr
sink
,
bool
color
)
{
if
(
color
)
//use color wrapper sink
sink
=
std
::
make_shared
<
spdlog
::
sinks
::
ansicolor_sink
>
(
sink
);
return
spdlog
::
details
::
registry
::
instance
().
create
(
logger_name
,
sink
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
stdout_logger_mt
(
const
std
::
string
&
logger_name
,
bool
color
)
{
return
create_console_logger
(
logger_name
,
sinks
::
stdout_sink_mt
::
instance
(),
color
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
stdout_logger_st
(
const
std
::
string
&
logger_name
,
bool
color
)
{
return
create_console_logger
(
logger_name
,
sinks
::
stdout_sink_st
::
instance
(),
color
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
stderr_logger_mt
(
const
std
::
string
&
logger_name
,
bool
color
)
{
return
create_console_logger
(
logger_name
,
sinks
::
stderr_sink_mt
::
instance
(),
color
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
stderr_logger_st
(
const
std
::
string
&
logger_name
,
bool
color
)
{
return
create_console_logger
(
logger_name
,
sinks
::
stderr_sink_st
::
instance
(),
color
);
}
#if defined(__linux__) || defined(__APPLE__)
// Create syslog logger
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
syslog_logger
(
const
std
::
string
&
logger_name
,
const
std
::
string
&
syslog_ident
,
int
syslog_option
)
{
return
create
<
spdlog
::
sinks
::
syslog_sink
>
(
logger_name
,
syslog_ident
,
syslog_option
);
}
#endif
//Create logger with multiple sinks
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
create
(
const
std
::
string
&
logger_name
,
spdlog
::
sinks_init_list
sinks
)
{
return
details
::
registry
::
instance
().
create
(
logger_name
,
sinks
);
}
template
<
typename
Sink
,
typename
...
Args
>
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
create
(
const
std
::
string
&
logger_name
,
Args
...
args
)
{
sink_ptr
sink
=
std
::
make_shared
<
Sink
>
(
args
...);
return
details
::
registry
::
instance
().
create
(
logger_name
,
{
sink
});
}
template
<
class
It
>
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
create
(
const
std
::
string
&
logger_name
,
const
It
&
sinks_begin
,
const
It
&
sinks_end
)
{
return
details
::
registry
::
instance
().
create
(
logger_name
,
sinks_begin
,
sinks_end
);
}
inline
void
spdlog
::
set_formatter
(
spdlog
::
formatter_ptr
f
)
{
details
::
registry
::
instance
().
formatter
(
f
);
}
inline
void
spdlog
::
set_pattern
(
const
std
::
string
&
format_string
)
{
return
details
::
registry
::
instance
().
set_pattern
(
format_string
);
}
inline
void
spdlog
::
set_level
(
level
::
level_enum
log_level
)
{
return
details
::
registry
::
instance
().
set_level
(
log_level
);
}
inline
void
spdlog
::
set_async_mode
(
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
)
{
details
::
registry
::
instance
().
set_async_mode
(
queue_size
,
overflow_policy
,
worker_warmup_cb
,
flush_interval_ms
);
}
inline
void
spdlog
::
set_sync_mode
()
{
details
::
registry
::
instance
().
set_sync_mode
();
}
inline
void
spdlog
::
drop_all
()
{
details
::
registry
::
instance
().
drop_all
();
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// Global registry functions
//
#include <spdlog/spdlog.h>
#include <spdlog/details/registry.h>
#include <spdlog/sinks/file_sinks.h>
#include <spdlog/sinks/stdout_sinks.h>
#include <spdlog/sinks/syslog_sink.h>
#include <spdlog/sinks/ansicolor_sink.h>
#include <chrono>
#include <functional>
#include <memory>
#include <string>
inline
void
spdlog
::
register_logger
(
std
::
shared_ptr
<
logger
>
logger
)
{
return
details
::
registry
::
instance
().
register_logger
(
logger
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
get
(
const
std
::
string
&
name
)
{
return
details
::
registry
::
instance
().
get
(
name
);
}
inline
void
spdlog
::
drop
(
const
std
::
string
&
name
)
{
details
::
registry
::
instance
().
drop
(
name
);
}
// Create multi/single threaded rotating file logger
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
rotating_logger_mt
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
size_t
max_file_size
,
size_t
max_files
,
bool
force_flush
)
{
return
create
<
spdlog
::
sinks
::
rotating_file_sink_mt
>
(
logger_name
,
filename
,
SPDLOG_FILENAME_T
(
"txt"
),
max_file_size
,
max_files
,
force_flush
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
rotating_logger_st
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
size_t
max_file_size
,
size_t
max_files
,
bool
force_flush
)
{
return
create
<
spdlog
::
sinks
::
rotating_file_sink_st
>
(
logger_name
,
filename
,
SPDLOG_FILENAME_T
(
"txt"
),
max_file_size
,
max_files
,
force_flush
);
}
// Create file logger which creates new file at midnight):
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
daily_logger_mt
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
int
hour
,
int
minute
,
bool
force_flush
)
{
return
create
<
spdlog
::
sinks
::
daily_file_sink_mt
>
(
logger_name
,
filename
,
SPDLOG_FILENAME_T
(
"txt"
),
hour
,
minute
,
force_flush
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
daily_logger_st
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
int
hour
,
int
minute
,
bool
force_flush
)
{
return
create
<
spdlog
::
sinks
::
daily_file_sink_st
>
(
logger_name
,
filename
,
SPDLOG_FILENAME_T
(
"txt"
),
hour
,
minute
,
force_flush
);
}
// Create stdout/stderr loggers (with optinal color support)
inline
std
::
shared_ptr
<
spdlog
::
logger
>
create_console_logger
(
const
std
::
string
&
logger_name
,
spdlog
::
sink_ptr
sink
,
bool
color
)
{
if
(
color
)
//use color wrapper sink
sink
=
std
::
make_shared
<
spdlog
::
sinks
::
ansicolor_sink
>
(
sink
);
return
spdlog
::
details
::
registry
::
instance
().
create
(
logger_name
,
sink
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
stdout_logger_mt
(
const
std
::
string
&
logger_name
,
bool
color
)
{
return
create_console_logger
(
logger_name
,
sinks
::
stdout_sink_mt
::
instance
(),
color
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
stdout_logger_st
(
const
std
::
string
&
logger_name
,
bool
color
)
{
return
create_console_logger
(
logger_name
,
sinks
::
stdout_sink_st
::
instance
(),
color
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
stderr_logger_mt
(
const
std
::
string
&
logger_name
,
bool
color
)
{
return
create_console_logger
(
logger_name
,
sinks
::
stderr_sink_mt
::
instance
(),
color
);
}
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
stderr_logger_st
(
const
std
::
string
&
logger_name
,
bool
color
)
{
return
create_console_logger
(
logger_name
,
sinks
::
stderr_sink_st
::
instance
(),
color
);
}
#if defined(__linux__) || defined(__APPLE__)
// Create syslog logger
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
syslog_logger
(
const
std
::
string
&
logger_name
,
const
std
::
string
&
syslog_ident
,
int
syslog_option
)
{
return
create
<
spdlog
::
sinks
::
syslog_sink
>
(
logger_name
,
syslog_ident
,
syslog_option
);
}
#endif
//Create logger with multiple sinks
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
create
(
const
std
::
string
&
logger_name
,
spdlog
::
sinks_init_list
sinks
)
{
return
details
::
registry
::
instance
().
create
(
logger_name
,
sinks
);
}
template
<
typename
Sink
,
typename
...
Args
>
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
create
(
const
std
::
string
&
logger_name
,
Args
...
args
)
{
sink_ptr
sink
=
std
::
make_shared
<
Sink
>
(
args
...);
return
details
::
registry
::
instance
().
create
(
logger_name
,
{
sink
});
}
template
<
class
It
>
inline
std
::
shared_ptr
<
spdlog
::
logger
>
spdlog
::
create
(
const
std
::
string
&
logger_name
,
const
It
&
sinks_begin
,
const
It
&
sinks_end
)
{
return
details
::
registry
::
instance
().
create
(
logger_name
,
sinks_begin
,
sinks_end
);
}
inline
void
spdlog
::
set_formatter
(
spdlog
::
formatter_ptr
f
)
{
details
::
registry
::
instance
().
formatter
(
f
);
}
inline
void
spdlog
::
set_pattern
(
const
std
::
string
&
format_string
)
{
return
details
::
registry
::
instance
().
set_pattern
(
format_string
);
}
inline
void
spdlog
::
set_level
(
level
::
level_enum
log_level
)
{
return
details
::
registry
::
instance
().
set_level
(
log_level
);
}
inline
void
spdlog
::
set_async_mode
(
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
)
{
details
::
registry
::
instance
().
set_async_mode
(
queue_size
,
overflow_policy
,
worker_warmup_cb
,
flush_interval_ms
);
}
inline
void
spdlog
::
set_sync_mode
()
{
details
::
registry
::
instance
().
set_sync_mode
();
}
inline
void
spdlog
::
drop_all
()
{
details
::
registry
::
instance
().
drop_all
();
}
include/spdlog/formatter.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/details/log_msg.h>
#include <vector>
#include <string>
#include <memory>
namespace
spdlog
{
namespace
details
{
class
flag_formatter
;
}
class
formatter
{
public:
virtual
~
formatter
()
{}
virtual
void
format
(
details
::
log_msg
&
msg
)
=
0
;
};
class
pattern_formatter
:
public
formatter
{
public:
explicit
pattern_formatter
(
const
std
::
string
&
pattern
);
pattern_formatter
(
const
pattern_formatter
&
)
=
delete
;
pattern_formatter
&
operator
=
(
const
pattern_formatter
&
)
=
delete
;
void
format
(
details
::
log_msg
&
msg
)
override
;
private:
const
std
::
string
_pattern
;
std
::
vector
<
std
::
unique_ptr
<
details
::
flag_formatter
>>
_formatters
;
void
handle_flag
(
char
flag
);
void
compile_pattern
(
const
std
::
string
&
pattern
);
};
}
#include <spdlog/details/pattern_formatter_impl.h>
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/details/log_msg.h>
#include <vector>
#include <string>
#include <memory>
namespace
spdlog
{
namespace
details
{
class
flag_formatter
;
}
class
formatter
{
public:
virtual
~
formatter
()
{}
virtual
void
format
(
details
::
log_msg
&
msg
)
=
0
;
};
class
pattern_formatter
:
public
formatter
{
public:
explicit
pattern_formatter
(
const
std
::
string
&
pattern
);
pattern_formatter
(
const
pattern_formatter
&
)
=
delete
;
pattern_formatter
&
operator
=
(
const
pattern_formatter
&
)
=
delete
;
void
format
(
details
::
log_msg
&
msg
)
override
;
private:
const
std
::
string
_pattern
;
std
::
vector
<
std
::
unique_ptr
<
details
::
flag_formatter
>>
_formatters
;
void
handle_flag
(
char
flag
);
void
compile_pattern
(
const
std
::
string
&
pattern
);
};
}
#include <spdlog/details/pattern_formatter_impl.h>
include/spdlog/logger.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Thread safe logger
// Has name, log level, vector of std::shared sink pointers and formatter
// Upon each log write the logger:
// 1. Checks if its log level is enough to log the message
// 2. Format the message using the formatter function
// 3. Pass the formatted message to its sinks to performa the actual logging
#include <spdlog/sinks/base_sink.h>
#include <spdlog/common.h>
#include <spdlog/details/line_logger_fwd.h>
#include <vector>
#include <memory>
#include <string>
namespace
spdlog
{
class
logger
{
public:
logger
(
const
std
::
string
&
logger_name
,
sink_ptr
single_sink
);
logger
(
const
std
::
string
&
name
,
sinks_init_list
);
template
<
class
It
>
logger
(
const
std
::
string
&
name
,
const
It
&
begin
,
const
It
&
end
);
virtual
~
logger
();
logger
(
const
logger
&
)
=
delete
;
logger
&
operator
=
(
const
logger
&
)
=
delete
;
void
set_level
(
level
::
level_enum
);
level
::
level_enum
level
()
const
;
const
std
::
string
&
name
()
const
;
bool
should_log
(
level
::
level_enum
)
const
;
// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
template
<
typename
...
Args
>
details
::
line_logger
trace
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
debug
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
info
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
notice
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
warn
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
error
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
critical
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
alert
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
emerg
(
const
char
*
fmt
,
const
Args
&
...
args
);
// logger.info(msg) << ".." call style
template
<
typename
T
>
details
::
line_logger
trace
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
debug
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
info
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
notice
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
warn
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
error
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
critical
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
alert
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
emerg
(
const
T
&
);
// logger.info() << ".." call style
details
::
line_logger
trace
();
details
::
line_logger
debug
();
details
::
line_logger
info
();
details
::
line_logger
notice
();
details
::
line_logger
warn
();
details
::
line_logger
error
();
details
::
line_logger
critical
();
details
::
line_logger
alert
();
details
::
line_logger
emerg
();
// Create log message with the given level, no matter what is the actual logger's level
template
<
typename
...
Args
>
details
::
line_logger
force_log
(
level
::
level_enum
lvl
,
const
char
*
fmt
,
const
Args
&
...
args
);
// Set the format of the log messages from this logger
void
set_pattern
(
const
std
::
string
&
);
void
set_formatter
(
formatter_ptr
);
virtual
void
flush
();
protected:
virtual
void
_log_msg
(
details
::
log_msg
&
);
virtual
void
_set_pattern
(
const
std
::
string
&
);
virtual
void
_set_formatter
(
formatter_ptr
);
details
::
line_logger
_log_if_enabled
(
level
::
level_enum
lvl
);
template
<
typename
...
Args
>
details
::
line_logger
_log_if_enabled
(
level
::
level_enum
lvl
,
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
T
>
inline
details
::
line_logger
_log_if_enabled
(
level
::
level_enum
lvl
,
const
T
&
msg
);
friend
details
::
line_logger
;
std
::
string
_name
;
std
::
vector
<
sink_ptr
>
_sinks
;
formatter_ptr
_formatter
;
spdlog
::
level_t
_level
;
};
}
#include <spdlog/details/logger_impl.h>
#include <spdlog/details/line_logger_impl.h>
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
// Thread safe logger
// Has name, log level, vector of std::shared sink pointers and formatter
// Upon each log write the logger:
// 1. Checks if its log level is enough to log the message
// 2. Format the message using the formatter function
// 3. Pass the formatted message to its sinks to performa the actual logging
#include <spdlog/sinks/base_sink.h>
#include <spdlog/common.h>
#include <spdlog/details/line_logger_fwd.h>
#include <vector>
#include <memory>
#include <string>
namespace
spdlog
{
class
logger
{
public:
logger
(
const
std
::
string
&
logger_name
,
sink_ptr
single_sink
);
logger
(
const
std
::
string
&
name
,
sinks_init_list
);
template
<
class
It
>
logger
(
const
std
::
string
&
name
,
const
It
&
begin
,
const
It
&
end
);
virtual
~
logger
();
logger
(
const
logger
&
)
=
delete
;
logger
&
operator
=
(
const
logger
&
)
=
delete
;
void
set_level
(
level
::
level_enum
);
level
::
level_enum
level
()
const
;
const
std
::
string
&
name
()
const
;
bool
should_log
(
level
::
level_enum
)
const
;
// logger.info(cppformat_string, arg1, arg2, arg3, ...) call style
template
<
typename
...
Args
>
details
::
line_logger
trace
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
debug
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
info
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
notice
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
warn
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
error
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
critical
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
alert
(
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
...
Args
>
details
::
line_logger
emerg
(
const
char
*
fmt
,
const
Args
&
...
args
);
// logger.info(msg) << ".." call style
template
<
typename
T
>
details
::
line_logger
trace
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
debug
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
info
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
notice
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
warn
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
error
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
critical
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
alert
(
const
T
&
);
template
<
typename
T
>
details
::
line_logger
emerg
(
const
T
&
);
// logger.info() << ".." call style
details
::
line_logger
trace
();
details
::
line_logger
debug
();
details
::
line_logger
info
();
details
::
line_logger
notice
();
details
::
line_logger
warn
();
details
::
line_logger
error
();
details
::
line_logger
critical
();
details
::
line_logger
alert
();
details
::
line_logger
emerg
();
// Create log message with the given level, no matter what is the actual logger's level
template
<
typename
...
Args
>
details
::
line_logger
force_log
(
level
::
level_enum
lvl
,
const
char
*
fmt
,
const
Args
&
...
args
);
// Set the format of the log messages from this logger
void
set_pattern
(
const
std
::
string
&
);
void
set_formatter
(
formatter_ptr
);
virtual
void
flush
();
protected:
virtual
void
_log_msg
(
details
::
log_msg
&
);
virtual
void
_set_pattern
(
const
std
::
string
&
);
virtual
void
_set_formatter
(
formatter_ptr
);
details
::
line_logger
_log_if_enabled
(
level
::
level_enum
lvl
);
template
<
typename
...
Args
>
details
::
line_logger
_log_if_enabled
(
level
::
level_enum
lvl
,
const
char
*
fmt
,
const
Args
&
...
args
);
template
<
typename
T
>
inline
details
::
line_logger
_log_if_enabled
(
level
::
level_enum
lvl
,
const
T
&
msg
);
friend
details
::
line_logger
;
std
::
string
_name
;
std
::
vector
<
sink_ptr
>
_sinks
;
formatter_ptr
_formatter
;
spdlog
::
level_t
_level
;
};
}
#include <spdlog/details/logger_impl.h>
#include <spdlog/details/line_logger_impl.h>
include/spdlog/sinks/android_sink.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#if defined(__ANDROID__)
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <android/log.h>
#include <mutex>
#include <string>
namespace
spdlog
{
namespace
sinks
{
/*
* Android sink (logging using __android_log_write)
*/
template
<
class
Mutex
>
class
base_android_sink
:
public
base_sink
<
Mutex
>
{
public:
explicit
base_android_sink
(
std
::
string
tag
=
"spdlog"
)
:
_tag
(
tag
)
{
}
void
flush
()
override
{
}
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
const
android_LogPriority
priority
=
convert_to_android
(
msg
.
level
);
const
int
expected_size
=
msg
.
formatted
.
size
();
const
int
size
=
__android_log_write
(
priority
,
_tag
.
c_str
(),
msg
.
formatted
.
c_str
()
);
if
(
size
>
expected_size
)
{
// Will write a little bit more than original message
}
else
{
throw
spdlog_ex
(
"Send to Android logcat failed"
);
}
}
private:
static
android_LogPriority
convert_to_android
(
spdlog
::
level
::
level_enum
level
)
{
switch
(
level
)
{
case
spdlog
:
:
level
::
trace
:
return
ANDROID_LOG_VERBOSE
;
case
spdlog
:
:
level
::
debug
:
return
ANDROID_LOG_DEBUG
;
case
spdlog
:
:
level
::
info
:
return
ANDROID_LOG_INFO
;
case
spdlog
:
:
level
::
notice
:
return
ANDROID_LOG_INFO
;
case
spdlog
:
:
level
::
warn
:
return
ANDROID_LOG_WARN
;
case
spdlog
:
:
level
::
err
:
return
ANDROID_LOG_ERROR
;
case
spdlog
:
:
level
::
critical
:
return
ANDROID_LOG_FATAL
;
case
spdlog
:
:
level
::
alert
:
return
ANDROID_LOG_FATAL
;
case
spdlog
:
:
level
::
emerg
:
return
ANDROID_LOG_FATAL
;
default:
throw
spdlog_ex
(
"Incorrect level value"
);
}
}
std
::
string
_tag
;
};
typedef
base_android_sink
<
std
::
mutex
>
android_sink_mt
;
typedef
base_android_sink
<
details
::
null_mutex
>
android_sink_st
;
}
}
#endif
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#if defined(__ANDROID__)
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <android/log.h>
#include <mutex>
#include <string>
namespace
spdlog
{
namespace
sinks
{
/*
* Android sink (logging using __android_log_write)
*/
template
<
class
Mutex
>
class
base_android_sink
:
public
base_sink
<
Mutex
>
{
public:
explicit
base_android_sink
(
std
::
string
tag
=
"spdlog"
)
:
_tag
(
tag
)
{
}
void
flush
()
override
{
}
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
const
android_LogPriority
priority
=
convert_to_android
(
msg
.
level
);
const
int
expected_size
=
msg
.
formatted
.
size
();
const
int
size
=
__android_log_write
(
priority
,
_tag
.
c_str
(),
msg
.
formatted
.
c_str
()
);
if
(
size
>
expected_size
)
{
// Will write a little bit more than original message
}
else
{
throw
spdlog_ex
(
"Send to Android logcat failed"
);
}
}
private:
static
android_LogPriority
convert_to_android
(
spdlog
::
level
::
level_enum
level
)
{
switch
(
level
)
{
case
spdlog
:
:
level
::
trace
:
return
ANDROID_LOG_VERBOSE
;
case
spdlog
:
:
level
::
debug
:
return
ANDROID_LOG_DEBUG
;
case
spdlog
:
:
level
::
info
:
return
ANDROID_LOG_INFO
;
case
spdlog
:
:
level
::
notice
:
return
ANDROID_LOG_INFO
;
case
spdlog
:
:
level
::
warn
:
return
ANDROID_LOG_WARN
;
case
spdlog
:
:
level
::
err
:
return
ANDROID_LOG_ERROR
;
case
spdlog
:
:
level
::
critical
:
return
ANDROID_LOG_FATAL
;
case
spdlog
:
:
level
::
alert
:
return
ANDROID_LOG_FATAL
;
case
spdlog
:
:
level
::
emerg
:
return
ANDROID_LOG_FATAL
;
default:
throw
spdlog_ex
(
"Incorrect level value"
);
}
}
std
::
string
_tag
;
};
typedef
base_android_sink
<
std
::
mutex
>
android_sink_mt
;
typedef
base_android_sink
<
details
::
null_mutex
>
android_sink_st
;
}
}
#endif
include/spdlog/sinks/ansicolor_sink.h
View file @
0d263598
//
// Copyright(c) 2016 Kevin M. Godby (a modified version by spdlog).
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/sinks/base_sink.h>
#include <spdlog/common.h>
#include <string>
#include <map>
namespace
spdlog
{
namespace
sinks
{
/**
* @brief The ansi_color_sink is a decorator around another sink and prefixes
* the output with an ANSI escape sequence color code depending on the severity
* of the message.
*/
class
ansicolor_sink
:
public
sink
{
public:
ansicolor_sink
(
sink_ptr
wrapped_sink
);
virtual
~
ansicolor_sink
();
ansicolor_sink
(
const
ansicolor_sink
&
other
)
=
delete
;
ansicolor_sink
&
operator
=
(
const
ansicolor_sink
&
other
)
=
delete
;
virtual
void
log
(
const
details
::
log_msg
&
msg
)
override
;
virtual
void
flush
()
override
;
void
set_color
(
level
::
level_enum
level
,
const
std
::
string
&
color
);
/// Formatting codes
const
std
::
string
reset
=
"
\033
[00m"
;
const
std
::
string
bold
=
"
\033
[1m"
;
const
std
::
string
dark
=
"
\033
[2m"
;
const
std
::
string
underline
=
"
\033
[4m"
;
const
std
::
string
blink
=
"
\033
[5m"
;
const
std
::
string
reverse
=
"
\033
[7m"
;
const
std
::
string
concealed
=
"
\033
[8m"
;
// Foreground colors
const
std
::
string
grey
=
"
\033
[30m"
;
const
std
::
string
red
=
"
\033
[31m"
;
const
std
::
string
green
=
"
\033
[32m"
;
const
std
::
string
yellow
=
"
\033
[33m"
;
const
std
::
string
blue
=
"
\033
[34m"
;
const
std
::
string
magenta
=
"
\033
[35m"
;
const
std
::
string
cyan
=
"
\033
[36m"
;
const
std
::
string
white
=
"
\033
[37m"
;
/// Background colors
const
std
::
string
on_grey
=
"
\033
[40m"
;
const
std
::
string
on_red
=
"
\033
[41m"
;
const
std
::
string
on_green
=
"
\033
[42m"
;
const
std
::
string
on_yellow
=
"
\033
[43m"
;
const
std
::
string
on_blue
=
"
\033
[44m"
;
const
std
::
string
on_magenta
=
"
\033
[45m"
;
const
std
::
string
on_cyan
=
"
\033
[46m"
;
const
std
::
string
on_white
=
"
\033
[47m"
;
protected:
sink_ptr
sink_
;
std
::
map
<
level
::
level_enum
,
std
::
string
>
colors_
;
};
inline
ansicolor_sink
::
ansicolor_sink
(
sink_ptr
wrapped_sink
)
:
sink_
(
wrapped_sink
)
{
colors_
[
level
::
trace
]
=
cyan
;
colors_
[
level
::
debug
]
=
cyan
;
colors_
[
level
::
info
]
=
white
;
colors_
[
level
::
notice
]
=
bold
+
white
;
colors_
[
level
::
warn
]
=
bold
+
yellow
;
colors_
[
level
::
err
]
=
red
;
colors_
[
level
::
critical
]
=
bold
+
red
;
colors_
[
level
::
alert
]
=
bold
+
white
+
on_red
;
colors_
[
level
::
emerg
]
=
bold
+
yellow
+
on_red
;
colors_
[
level
::
off
]
=
reset
;
}
inline
void
ansicolor_sink
::
log
(
const
details
::
log_msg
&
msg
)
{
// Wrap the originally formatted message in color codes
const
std
::
string
&
prefix
=
colors_
[
msg
.
level
];
const
std
::
string
&
s
=
msg
.
formatted
.
str
();
const
std
::
string
&
suffix
=
reset
;
details
::
log_msg
m
;
m
.
formatted
<<
prefix
<<
s
<<
suffix
;
sink_
->
log
(
m
);
}
inline
void
ansicolor_sink
::
flush
()
{
sink_
->
flush
();
}
inline
void
ansicolor_sink
::
set_color
(
level
::
level_enum
level
,
const
std
::
string
&
color
)
{
colors_
[
level
]
=
color
;
}
inline
ansicolor_sink
::~
ansicolor_sink
()
{
flush
();
}
}
// namespace sinks
}
// namespace spdlog
//
// Copyright(c) 2016 Kevin M. Godby (a modified version by spdlog).
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/sinks/base_sink.h>
#include <spdlog/common.h>
#include <string>
#include <map>
namespace
spdlog
{
namespace
sinks
{
/**
* @brief The ansi_color_sink is a decorator around another sink and prefixes
* the output with an ANSI escape sequence color code depending on the severity
* of the message.
*/
class
ansicolor_sink
:
public
sink
{
public:
ansicolor_sink
(
sink_ptr
wrapped_sink
);
virtual
~
ansicolor_sink
();
ansicolor_sink
(
const
ansicolor_sink
&
other
)
=
delete
;
ansicolor_sink
&
operator
=
(
const
ansicolor_sink
&
other
)
=
delete
;
virtual
void
log
(
const
details
::
log_msg
&
msg
)
override
;
virtual
void
flush
()
override
;
void
set_color
(
level
::
level_enum
level
,
const
std
::
string
&
color
);
/// Formatting codes
const
std
::
string
reset
=
"
\033
[00m"
;
const
std
::
string
bold
=
"
\033
[1m"
;
const
std
::
string
dark
=
"
\033
[2m"
;
const
std
::
string
underline
=
"
\033
[4m"
;
const
std
::
string
blink
=
"
\033
[5m"
;
const
std
::
string
reverse
=
"
\033
[7m"
;
const
std
::
string
concealed
=
"
\033
[8m"
;
// Foreground colors
const
std
::
string
grey
=
"
\033
[30m"
;
const
std
::
string
red
=
"
\033
[31m"
;
const
std
::
string
green
=
"
\033
[32m"
;
const
std
::
string
yellow
=
"
\033
[33m"
;
const
std
::
string
blue
=
"
\033
[34m"
;
const
std
::
string
magenta
=
"
\033
[35m"
;
const
std
::
string
cyan
=
"
\033
[36m"
;
const
std
::
string
white
=
"
\033
[37m"
;
/// Background colors
const
std
::
string
on_grey
=
"
\033
[40m"
;
const
std
::
string
on_red
=
"
\033
[41m"
;
const
std
::
string
on_green
=
"
\033
[42m"
;
const
std
::
string
on_yellow
=
"
\033
[43m"
;
const
std
::
string
on_blue
=
"
\033
[44m"
;
const
std
::
string
on_magenta
=
"
\033
[45m"
;
const
std
::
string
on_cyan
=
"
\033
[46m"
;
const
std
::
string
on_white
=
"
\033
[47m"
;
protected:
sink_ptr
sink_
;
std
::
map
<
level
::
level_enum
,
std
::
string
>
colors_
;
};
inline
ansicolor_sink
::
ansicolor_sink
(
sink_ptr
wrapped_sink
)
:
sink_
(
wrapped_sink
)
{
colors_
[
level
::
trace
]
=
cyan
;
colors_
[
level
::
debug
]
=
cyan
;
colors_
[
level
::
info
]
=
white
;
colors_
[
level
::
notice
]
=
bold
+
white
;
colors_
[
level
::
warn
]
=
bold
+
yellow
;
colors_
[
level
::
err
]
=
red
;
colors_
[
level
::
critical
]
=
bold
+
red
;
colors_
[
level
::
alert
]
=
bold
+
white
+
on_red
;
colors_
[
level
::
emerg
]
=
bold
+
yellow
+
on_red
;
colors_
[
level
::
off
]
=
reset
;
}
inline
void
ansicolor_sink
::
log
(
const
details
::
log_msg
&
msg
)
{
// Wrap the originally formatted message in color codes
const
std
::
string
&
prefix
=
colors_
[
msg
.
level
];
const
std
::
string
&
s
=
msg
.
formatted
.
str
();
const
std
::
string
&
suffix
=
reset
;
details
::
log_msg
m
;
m
.
formatted
<<
prefix
<<
s
<<
suffix
;
sink_
->
log
(
m
);
}
inline
void
ansicolor_sink
::
flush
()
{
sink_
->
flush
();
}
inline
void
ansicolor_sink
::
set_color
(
level
::
level_enum
level
,
const
std
::
string
&
color
)
{
colors_
[
level
]
=
color
;
}
inline
ansicolor_sink
::~
ansicolor_sink
()
{
flush
();
}
}
// namespace sinks
}
// namespace spdlog
include/spdlog/sinks/base_sink.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// base sink templated over a mutex (either dummy or realy)
// concrete implementation should only overrid the _sink_it method.
// all locking is taken care of here so no locking needed by the implementors..
//
#include <spdlog/sinks/sink.h>
#include <spdlog/formatter.h>
#include <spdlog/common.h>
#include <spdlog/details/log_msg.h>
#include <mutex>
namespace
spdlog
{
namespace
sinks
{
template
<
class
Mutex
>
class
base_sink
:
public
sink
{
public:
base_sink
()
:
_mutex
()
{}
virtual
~
base_sink
()
=
default
;
base_sink
(
const
base_sink
&
)
=
delete
;
base_sink
&
operator
=
(
const
base_sink
&
)
=
delete
;
void
log
(
const
details
::
log_msg
&
msg
)
override
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_sink_it
(
msg
);
}
protected:
virtual
void
_sink_it
(
const
details
::
log_msg
&
msg
)
=
0
;
Mutex
_mutex
;
};
}
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
//
// base sink templated over a mutex (either dummy or realy)
// concrete implementation should only overrid the _sink_it method.
// all locking is taken care of here so no locking needed by the implementors..
//
#include <spdlog/sinks/sink.h>
#include <spdlog/formatter.h>
#include <spdlog/common.h>
#include <spdlog/details/log_msg.h>
#include <mutex>
namespace
spdlog
{
namespace
sinks
{
template
<
class
Mutex
>
class
base_sink
:
public
sink
{
public:
base_sink
()
:
_mutex
()
{}
virtual
~
base_sink
()
=
default
;
base_sink
(
const
base_sink
&
)
=
delete
;
base_sink
&
operator
=
(
const
base_sink
&
)
=
delete
;
void
log
(
const
details
::
log_msg
&
msg
)
override
{
std
::
lock_guard
<
Mutex
>
lock
(
_mutex
);
_sink_it
(
msg
);
}
protected:
virtual
void
_sink_it
(
const
details
::
log_msg
&
msg
)
=
0
;
Mutex
_mutex
;
};
}
}
include/spdlog/sinks/dist_sink.h
View file @
0d263598
//
// Copyright (c) 2015 David Schury, Gabi Melman
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/details/log_msg.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/sinks/sink.h>
#include <algorithm>
#include <memory>
#include <mutex>
#include <vector>
namespace
spdlog
{
namespace
sinks
{
template
<
class
Mutex
>
class
dist_sink
:
public
base_sink
<
Mutex
>
{
public:
explicit
dist_sink
()
:
_sinks
()
{}
dist_sink
(
const
dist_sink
&
)
=
delete
;
dist_sink
&
operator
=
(
const
dist_sink
&
)
=
delete
;
virtual
~
dist_sink
()
=
default
;
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
for
(
auto
iter
=
_sinks
.
begin
();
iter
!=
_sinks
.
end
();
iter
++
)
(
*
iter
)
->
log
(
msg
);
}
std
::
vector
<
std
::
shared_ptr
<
sink
>>
_sinks
;
public:
void
flush
()
override
{
std
::
lock_guard
<
Mutex
>
lock
(
base_sink
<
Mutex
>::
_mutex
);
for
(
auto
iter
=
_sinks
.
begin
();
iter
!=
_sinks
.
end
();
iter
++
)
(
*
iter
)
->
flush
();
}
void
add_sink
(
std
::
shared_ptr
<
sink
>
sink
)
{
std
::
lock_guard
<
Mutex
>
lock
(
base_sink
<
Mutex
>::
_mutex
);
if
(
sink
&&
_sinks
.
end
()
==
std
::
find
(
_sinks
.
begin
(),
_sinks
.
end
(),
sink
))
{
_sinks
.
push_back
(
sink
);
}
}
void
remove_sink
(
std
::
shared_ptr
<
sink
>
sink
)
{
std
::
lock_guard
<
Mutex
>
lock
(
base_sink
<
Mutex
>::
_mutex
);
auto
pos
=
std
::
find
(
_sinks
.
begin
(),
_sinks
.
end
(),
sink
);
if
(
pos
!=
_sinks
.
end
())
{
_sinks
.
erase
(
pos
);
}
}
};
typedef
dist_sink
<
std
::
mutex
>
dist_sink_mt
;
typedef
dist_sink
<
details
::
null_mutex
>
dist_sink_st
;
}
}
//
// Copyright (c) 2015 David Schury, Gabi Melman
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/details/log_msg.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/sinks/base_sink.h>
#include <spdlog/sinks/sink.h>
#include <algorithm>
#include <memory>
#include <mutex>
#include <vector>
namespace
spdlog
{
namespace
sinks
{
template
<
class
Mutex
>
class
dist_sink
:
public
base_sink
<
Mutex
>
{
public:
explicit
dist_sink
()
:
_sinks
()
{}
dist_sink
(
const
dist_sink
&
)
=
delete
;
dist_sink
&
operator
=
(
const
dist_sink
&
)
=
delete
;
virtual
~
dist_sink
()
=
default
;
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
for
(
auto
iter
=
_sinks
.
begin
();
iter
!=
_sinks
.
end
();
iter
++
)
(
*
iter
)
->
log
(
msg
);
}
std
::
vector
<
std
::
shared_ptr
<
sink
>>
_sinks
;
public:
void
flush
()
override
{
std
::
lock_guard
<
Mutex
>
lock
(
base_sink
<
Mutex
>::
_mutex
);
for
(
auto
iter
=
_sinks
.
begin
();
iter
!=
_sinks
.
end
();
iter
++
)
(
*
iter
)
->
flush
();
}
void
add_sink
(
std
::
shared_ptr
<
sink
>
sink
)
{
std
::
lock_guard
<
Mutex
>
lock
(
base_sink
<
Mutex
>::
_mutex
);
if
(
sink
&&
_sinks
.
end
()
==
std
::
find
(
_sinks
.
begin
(),
_sinks
.
end
(),
sink
))
{
_sinks
.
push_back
(
sink
);
}
}
void
remove_sink
(
std
::
shared_ptr
<
sink
>
sink
)
{
std
::
lock_guard
<
Mutex
>
lock
(
base_sink
<
Mutex
>::
_mutex
);
auto
pos
=
std
::
find
(
_sinks
.
begin
(),
_sinks
.
end
(),
sink
);
if
(
pos
!=
_sinks
.
end
())
{
_sinks
.
erase
(
pos
);
}
}
};
typedef
dist_sink
<
std
::
mutex
>
dist_sink_mt
;
typedef
dist_sink
<
details
::
null_mutex
>
dist_sink_st
;
}
}
include/spdlog/sinks/file_sinks.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/details/file_helper.h>
#include <spdlog/details/format.h>
#include <algorithm>
#include <chrono>
#include <cstdio>
#include <ctime>
#include <mutex>
#include <string>
namespace
spdlog
{
namespace
sinks
{
/*
* Trivial file sink with single file as target
*/
template
<
class
Mutex
>
class
simple_file_sink
:
public
base_sink
<
Mutex
>
{
public:
explicit
simple_file_sink
(
const
filename_t
&
filename
,
bool
force_flush
=
false
)
:
_file_helper
(
force_flush
)
{
_file_helper
.
open
(
filename
);
}
void
flush
()
override
{
_file_helper
.
flush
();
}
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
_file_helper
.
write
(
msg
);
}
private:
details
::
file_helper
_file_helper
;
};
typedef
simple_file_sink
<
std
::
mutex
>
simple_file_sink_mt
;
typedef
simple_file_sink
<
details
::
null_mutex
>
simple_file_sink_st
;
/*
* Rotating file sink based on size
*/
template
<
class
Mutex
>
class
rotating_file_sink
:
public
base_sink
<
Mutex
>
{
public:
rotating_file_sink
(
const
filename_t
&
base_filename
,
const
filename_t
&
extension
,
std
::
size_t
max_size
,
std
::
size_t
max_files
,
bool
force_flush
=
false
)
:
_base_filename
(
base_filename
),
_extension
(
extension
),
_max_size
(
max_size
),
_max_files
(
max_files
),
_current_size
(
0
),
_file_helper
(
force_flush
)
{
_file_helper
.
open
(
calc_filename
(
_base_filename
,
0
,
_extension
));
_current_size
=
_file_helper
.
size
();
//expensive. called only once
}
void
flush
()
override
{
_file_helper
.
flush
();
}
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
_current_size
+=
msg
.
formatted
.
size
();
if
(
_current_size
>
_max_size
)
{
_rotate
();
_current_size
=
msg
.
formatted
.
size
();
}
_file_helper
.
write
(
msg
);
}
private:
static
filename_t
calc_filename
(
const
filename_t
&
filename
,
std
::
size_t
index
,
const
filename_t
&
extension
)
{
std
::
conditional
<
std
::
is_same
<
filename_t
::
value_type
,
char
>::
value
,
fmt
::
MemoryWriter
,
fmt
::
WMemoryWriter
>::
type
w
;
if
(
index
)
w
.
write
(
SPDLOG_FILENAME_T
(
"{}.{}.{}"
),
filename
,
index
,
extension
);
else
w
.
write
(
SPDLOG_FILENAME_T
(
"{}.{}"
),
filename
,
extension
);
return
w
.
str
();
}
// Rotate files:
// log.txt -> log.1.txt
// log.1.txt -> log2.txt
// log.2.txt -> log3.txt
// log.3.txt -> delete
void
_rotate
()
{
_file_helper
.
close
();
for
(
auto
i
=
_max_files
;
i
>
0
;
--
i
)
{
filename_t
src
=
calc_filename
(
_base_filename
,
i
-
1
,
_extension
);
filename_t
target
=
calc_filename
(
_base_filename
,
i
,
_extension
);
if
(
details
::
file_helper
::
file_exists
(
target
))
{
if
(
details
::
os
::
remove
(
target
)
!=
0
)
{
throw
spdlog_ex
(
"rotating_file_sink: failed removing "
+
filename_to_str
(
target
));
}
}
if
(
details
::
file_helper
::
file_exists
(
src
)
&&
details
::
os
::
rename
(
src
,
target
))
{
throw
spdlog_ex
(
"rotating_file_sink: failed renaming "
+
filename_to_str
(
src
)
+
" to "
+
filename_to_str
(
target
));
}
}
_file_helper
.
reopen
(
true
);
}
filename_t
_base_filename
;
filename_t
_extension
;
std
::
size_t
_max_size
;
std
::
size_t
_max_files
;
std
::
size_t
_current_size
;
details
::
file_helper
_file_helper
;
};
typedef
rotating_file_sink
<
std
::
mutex
>
rotating_file_sink_mt
;
typedef
rotating_file_sink
<
details
::
null_mutex
>
rotating_file_sink_st
;
/*
* Rotating file sink based on date. rotates at midnight
*/
template
<
class
Mutex
>
class
daily_file_sink
:
public
base_sink
<
Mutex
>
{
public:
//create daily file sink which rotates on given time
daily_file_sink
(
const
filename_t
&
base_filename
,
const
filename_t
&
extension
,
int
rotation_hour
,
int
rotation_minute
,
bool
force_flush
=
false
)
:
_base_filename
(
base_filename
),
_extension
(
extension
),
_rotation_h
(
rotation_hour
),
_rotation_m
(
rotation_minute
),
_file_helper
(
force_flush
)
{
if
(
rotation_hour
<
0
||
rotation_hour
>
23
||
rotation_minute
<
0
||
rotation_minute
>
59
)
throw
spdlog_ex
(
"daily_file_sink: Invalid rotation time in ctor"
);
_rotation_tp
=
_next_rotation_tp
();
_file_helper
.
open
(
calc_filename
(
_base_filename
,
_extension
));
}
void
flush
()
override
{
_file_helper
.
flush
();
}
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
if
(
std
::
chrono
::
system_clock
::
now
()
>=
_rotation_tp
)
{
_file_helper
.
open
(
calc_filename
(
_base_filename
,
_extension
));
_rotation_tp
=
_next_rotation_tp
();
}
_file_helper
.
write
(
msg
);
}
private:
std
::
chrono
::
system_clock
::
time_point
_next_rotation_tp
()
{
using
namespace
std
::
chrono
;
auto
now
=
system_clock
::
now
();
time_t
tnow
=
std
::
chrono
::
system_clock
::
to_time_t
(
now
);
tm
date
=
spdlog
::
details
::
os
::
localtime
(
tnow
);
date
.
tm_hour
=
_rotation_h
;
date
.
tm_min
=
_rotation_m
;
date
.
tm_sec
=
0
;
auto
rotation_time
=
std
::
chrono
::
system_clock
::
from_time_t
(
std
::
mktime
(
&
date
));
if
(
rotation_time
>
now
)
return
rotation_time
;
else
return
system_clock
::
time_point
(
rotation_time
+
hours
(
24
));
}
//Create filename for the form basename.YYYY-MM-DD.extension
static
filename_t
calc_filename
(
const
filename_t
&
basename
,
const
filename_t
&
extension
)
{
std
::
tm
tm
=
spdlog
::
details
::
os
::
localtime
();
std
::
conditional
<
std
::
is_same
<
filename_t
::
value_type
,
char
>::
value
,
fmt
::
MemoryWriter
,
fmt
::
WMemoryWriter
>::
type
w
;
w
.
write
(
SPDLOG_FILENAME_T
(
"{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.{}"
),
basename
,
tm
.
tm_year
+
1900
,
tm
.
tm_mon
+
1
,
tm
.
tm_mday
,
tm
.
tm_hour
,
tm
.
tm_min
,
extension
);
return
w
.
str
();
}
filename_t
_base_filename
;
filename_t
_extension
;
int
_rotation_h
;
int
_rotation_m
;
std
::
chrono
::
system_clock
::
time_point
_rotation_tp
;
details
::
file_helper
_file_helper
;
};
typedef
daily_file_sink
<
std
::
mutex
>
daily_file_sink_mt
;
typedef
daily_file_sink
<
details
::
null_mutex
>
daily_file_sink_st
;
}
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <spdlog/details/file_helper.h>
#include <spdlog/details/format.h>
#include <algorithm>
#include <chrono>
#include <cstdio>
#include <ctime>
#include <mutex>
#include <string>
namespace
spdlog
{
namespace
sinks
{
/*
* Trivial file sink with single file as target
*/
template
<
class
Mutex
>
class
simple_file_sink
:
public
base_sink
<
Mutex
>
{
public:
explicit
simple_file_sink
(
const
filename_t
&
filename
,
bool
force_flush
=
false
)
:
_file_helper
(
force_flush
)
{
_file_helper
.
open
(
filename
);
}
void
flush
()
override
{
_file_helper
.
flush
();
}
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
_file_helper
.
write
(
msg
);
}
private:
details
::
file_helper
_file_helper
;
};
typedef
simple_file_sink
<
std
::
mutex
>
simple_file_sink_mt
;
typedef
simple_file_sink
<
details
::
null_mutex
>
simple_file_sink_st
;
/*
* Rotating file sink based on size
*/
template
<
class
Mutex
>
class
rotating_file_sink
:
public
base_sink
<
Mutex
>
{
public:
rotating_file_sink
(
const
filename_t
&
base_filename
,
const
filename_t
&
extension
,
std
::
size_t
max_size
,
std
::
size_t
max_files
,
bool
force_flush
=
false
)
:
_base_filename
(
base_filename
),
_extension
(
extension
),
_max_size
(
max_size
),
_max_files
(
max_files
),
_current_size
(
0
),
_file_helper
(
force_flush
)
{
_file_helper
.
open
(
calc_filename
(
_base_filename
,
0
,
_extension
));
_current_size
=
_file_helper
.
size
();
//expensive. called only once
}
void
flush
()
override
{
_file_helper
.
flush
();
}
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
_current_size
+=
msg
.
formatted
.
size
();
if
(
_current_size
>
_max_size
)
{
_rotate
();
_current_size
=
msg
.
formatted
.
size
();
}
_file_helper
.
write
(
msg
);
}
private:
static
filename_t
calc_filename
(
const
filename_t
&
filename
,
std
::
size_t
index
,
const
filename_t
&
extension
)
{
std
::
conditional
<
std
::
is_same
<
filename_t
::
value_type
,
char
>::
value
,
fmt
::
MemoryWriter
,
fmt
::
WMemoryWriter
>::
type
w
;
if
(
index
)
w
.
write
(
SPDLOG_FILENAME_T
(
"{}.{}.{}"
),
filename
,
index
,
extension
);
else
w
.
write
(
SPDLOG_FILENAME_T
(
"{}.{}"
),
filename
,
extension
);
return
w
.
str
();
}
// Rotate files:
// log.txt -> log.1.txt
// log.1.txt -> log2.txt
// log.2.txt -> log3.txt
// log.3.txt -> delete
void
_rotate
()
{
_file_helper
.
close
();
for
(
auto
i
=
_max_files
;
i
>
0
;
--
i
)
{
filename_t
src
=
calc_filename
(
_base_filename
,
i
-
1
,
_extension
);
filename_t
target
=
calc_filename
(
_base_filename
,
i
,
_extension
);
if
(
details
::
file_helper
::
file_exists
(
target
))
{
if
(
details
::
os
::
remove
(
target
)
!=
0
)
{
throw
spdlog_ex
(
"rotating_file_sink: failed removing "
+
filename_to_str
(
target
));
}
}
if
(
details
::
file_helper
::
file_exists
(
src
)
&&
details
::
os
::
rename
(
src
,
target
))
{
throw
spdlog_ex
(
"rotating_file_sink: failed renaming "
+
filename_to_str
(
src
)
+
" to "
+
filename_to_str
(
target
));
}
}
_file_helper
.
reopen
(
true
);
}
filename_t
_base_filename
;
filename_t
_extension
;
std
::
size_t
_max_size
;
std
::
size_t
_max_files
;
std
::
size_t
_current_size
;
details
::
file_helper
_file_helper
;
};
typedef
rotating_file_sink
<
std
::
mutex
>
rotating_file_sink_mt
;
typedef
rotating_file_sink
<
details
::
null_mutex
>
rotating_file_sink_st
;
/*
* Rotating file sink based on date. rotates at midnight
*/
template
<
class
Mutex
>
class
daily_file_sink
:
public
base_sink
<
Mutex
>
{
public:
//create daily file sink which rotates on given time
daily_file_sink
(
const
filename_t
&
base_filename
,
const
filename_t
&
extension
,
int
rotation_hour
,
int
rotation_minute
,
bool
force_flush
=
false
)
:
_base_filename
(
base_filename
),
_extension
(
extension
),
_rotation_h
(
rotation_hour
),
_rotation_m
(
rotation_minute
),
_file_helper
(
force_flush
)
{
if
(
rotation_hour
<
0
||
rotation_hour
>
23
||
rotation_minute
<
0
||
rotation_minute
>
59
)
throw
spdlog_ex
(
"daily_file_sink: Invalid rotation time in ctor"
);
_rotation_tp
=
_next_rotation_tp
();
_file_helper
.
open
(
calc_filename
(
_base_filename
,
_extension
));
}
void
flush
()
override
{
_file_helper
.
flush
();
}
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
if
(
std
::
chrono
::
system_clock
::
now
()
>=
_rotation_tp
)
{
_file_helper
.
open
(
calc_filename
(
_base_filename
,
_extension
));
_rotation_tp
=
_next_rotation_tp
();
}
_file_helper
.
write
(
msg
);
}
private:
std
::
chrono
::
system_clock
::
time_point
_next_rotation_tp
()
{
using
namespace
std
::
chrono
;
auto
now
=
system_clock
::
now
();
time_t
tnow
=
std
::
chrono
::
system_clock
::
to_time_t
(
now
);
tm
date
=
spdlog
::
details
::
os
::
localtime
(
tnow
);
date
.
tm_hour
=
_rotation_h
;
date
.
tm_min
=
_rotation_m
;
date
.
tm_sec
=
0
;
auto
rotation_time
=
std
::
chrono
::
system_clock
::
from_time_t
(
std
::
mktime
(
&
date
));
if
(
rotation_time
>
now
)
return
rotation_time
;
else
return
system_clock
::
time_point
(
rotation_time
+
hours
(
24
));
}
//Create filename for the form basename.YYYY-MM-DD.extension
static
filename_t
calc_filename
(
const
filename_t
&
basename
,
const
filename_t
&
extension
)
{
std
::
tm
tm
=
spdlog
::
details
::
os
::
localtime
();
std
::
conditional
<
std
::
is_same
<
filename_t
::
value_type
,
char
>::
value
,
fmt
::
MemoryWriter
,
fmt
::
WMemoryWriter
>::
type
w
;
w
.
write
(
SPDLOG_FILENAME_T
(
"{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.{}"
),
basename
,
tm
.
tm_year
+
1900
,
tm
.
tm_mon
+
1
,
tm
.
tm_mday
,
tm
.
tm_hour
,
tm
.
tm_min
,
extension
);
return
w
.
str
();
}
filename_t
_base_filename
;
filename_t
_extension
;
int
_rotation_h
;
int
_rotation_m
;
std
::
chrono
::
system_clock
::
time_point
_rotation_tp
;
details
::
file_helper
_file_helper
;
};
typedef
daily_file_sink
<
std
::
mutex
>
daily_file_sink_mt
;
typedef
daily_file_sink
<
details
::
null_mutex
>
daily_file_sink_st
;
}
}
include/spdlog/sinks/msvc_sink.h
View file @
0d263598
//
// Copyright(c) 2016 Alexander Dalshov.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#if defined(_MSC_VER)
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <WinBase.h>
#include <mutex>
#include <string>
namespace
spdlog
{
namespace
sinks
{
/*
* MSVC sink (logging using OutputDebugStringA)
*/
template
<
class
Mutex
>
class
msvc_sink
:
public
base_sink
<
Mutex
>
{
public:
explicit
msvc_sink
()
{
}
void
flush
()
override
{
}
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
OutputDebugStringA
(
msg
.
formatted
.
c_str
());
}
};
typedef
msvc_sink
<
std
::
mutex
>
msvc_sink_mt
;
typedef
msvc_sink
<
details
::
null_mutex
>
msvc_sink_st
;
}
}
#endif
//
// Copyright(c) 2016 Alexander Dalshov.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#if defined(_MSC_VER)
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <WinBase.h>
#include <mutex>
#include <string>
namespace
spdlog
{
namespace
sinks
{
/*
* MSVC sink (logging using OutputDebugStringA)
*/
template
<
class
Mutex
>
class
msvc_sink
:
public
base_sink
<
Mutex
>
{
public:
explicit
msvc_sink
()
{
}
void
flush
()
override
{
}
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
OutputDebugStringA
(
msg
.
formatted
.
c_str
());
}
};
typedef
msvc_sink
<
std
::
mutex
>
msvc_sink_mt
;
typedef
msvc_sink
<
details
::
null_mutex
>
msvc_sink_st
;
}
}
#endif
include/spdlog/sinks/null_sink.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <mutex>
namespace
spdlog
{
namespace
sinks
{
template
<
class
Mutex
>
class
null_sink
:
public
base_sink
<
Mutex
>
{
protected:
void
_sink_it
(
const
details
::
log_msg
&
)
override
{}
void
flush
()
override
{}
};
typedef
null_sink
<
details
::
null_mutex
>
null_sink_st
;
typedef
null_sink
<
std
::
mutex
>
null_sink_mt
;
}
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/sinks/base_sink.h>
#include <spdlog/details/null_mutex.h>
#include <mutex>
namespace
spdlog
{
namespace
sinks
{
template
<
class
Mutex
>
class
null_sink
:
public
base_sink
<
Mutex
>
{
protected:
void
_sink_it
(
const
details
::
log_msg
&
)
override
{}
void
flush
()
override
{}
};
typedef
null_sink
<
details
::
null_mutex
>
null_sink_st
;
typedef
null_sink
<
std
::
mutex
>
null_sink_mt
;
}
}
include/spdlog/sinks/ostream_sink.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/details/null_mutex.h>
#include <spdlog/sinks/base_sink.h>
#include <ostream>
#include <mutex>
namespace
spdlog
{
namespace
sinks
{
template
<
class
Mutex
>
class
ostream_sink
:
public
base_sink
<
Mutex
>
{
public:
explicit
ostream_sink
(
std
::
ostream
&
os
,
bool
force_flush
=
false
)
:
_ostream
(
os
),
_force_flush
(
force_flush
)
{}
ostream_sink
(
const
ostream_sink
&
)
=
delete
;
ostream_sink
&
operator
=
(
const
ostream_sink
&
)
=
delete
;
virtual
~
ostream_sink
()
=
default
;
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
_ostream
.
write
(
msg
.
formatted
.
data
(),
msg
.
formatted
.
size
());
if
(
_force_flush
)
_ostream
.
flush
();
}
void
flush
()
override
{
_ostream
.
flush
();
}
std
::
ostream
&
_ostream
;
bool
_force_flush
;
};
typedef
ostream_sink
<
std
::
mutex
>
ostream_sink_mt
;
typedef
ostream_sink
<
details
::
null_mutex
>
ostream_sink_st
;
}
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/details/null_mutex.h>
#include <spdlog/sinks/base_sink.h>
#include <ostream>
#include <mutex>
namespace
spdlog
{
namespace
sinks
{
template
<
class
Mutex
>
class
ostream_sink
:
public
base_sink
<
Mutex
>
{
public:
explicit
ostream_sink
(
std
::
ostream
&
os
,
bool
force_flush
=
false
)
:
_ostream
(
os
),
_force_flush
(
force_flush
)
{}
ostream_sink
(
const
ostream_sink
&
)
=
delete
;
ostream_sink
&
operator
=
(
const
ostream_sink
&
)
=
delete
;
virtual
~
ostream_sink
()
=
default
;
protected:
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
_ostream
.
write
(
msg
.
formatted
.
data
(),
msg
.
formatted
.
size
());
if
(
_force_flush
)
_ostream
.
flush
();
}
void
flush
()
override
{
_ostream
.
flush
();
}
std
::
ostream
&
_ostream
;
bool
_force_flush
;
};
typedef
ostream_sink
<
std
::
mutex
>
ostream_sink_mt
;
typedef
ostream_sink
<
details
::
null_mutex
>
ostream_sink_st
;
}
}
include/spdlog/sinks/sink.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/details/log_msg.h>
namespace
spdlog
{
namespace
sinks
{
class
sink
{
public:
virtual
~
sink
()
{}
virtual
void
log
(
const
details
::
log_msg
&
msg
)
=
0
;
virtual
void
flush
()
=
0
;
};
}
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/details/log_msg.h>
namespace
spdlog
{
namespace
sinks
{
class
sink
{
public:
virtual
~
sink
()
{}
virtual
void
log
(
const
details
::
log_msg
&
msg
)
=
0
;
virtual
void
flush
()
=
0
;
};
}
}
include/spdlog/sinks/stdout_sinks.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/details/null_mutex.h>
#include <cstdio>
#include <memory>
#include <mutex>
namespace
spdlog
{
namespace
sinks
{
template
<
class
Mutex
>
class
stdout_sink
:
public
base_sink
<
Mutex
>
{
using
MyType
=
stdout_sink
<
Mutex
>
;
public:
stdout_sink
()
{}
static
std
::
shared_ptr
<
MyType
>
instance
()
{
static
std
::
shared_ptr
<
MyType
>
instance
=
std
::
make_shared
<
MyType
>
();
return
instance
;
}
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
fwrite
(
msg
.
formatted
.
data
(),
sizeof
(
char
),
msg
.
formatted
.
size
(),
stdout
);
flush
();
}
void
flush
()
override
{
fflush
(
stdout
);
}
};
typedef
stdout_sink
<
details
::
null_mutex
>
stdout_sink_st
;
typedef
stdout_sink
<
std
::
mutex
>
stdout_sink_mt
;
template
<
class
Mutex
>
class
stderr_sink
:
public
base_sink
<
Mutex
>
{
using
MyType
=
stderr_sink
<
Mutex
>
;
public:
stderr_sink
()
{}
static
std
::
shared_ptr
<
MyType
>
instance
()
{
static
std
::
shared_ptr
<
MyType
>
instance
=
std
::
make_shared
<
MyType
>
();
return
instance
;
}
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
fwrite
(
msg
.
formatted
.
data
(),
sizeof
(
char
),
msg
.
formatted
.
size
(),
stderr
);
flush
();
}
void
flush
()
override
{
fflush
(
stderr
);
}
};
typedef
stderr_sink
<
std
::
mutex
>
stderr_sink_mt
;
typedef
stderr_sink
<
details
::
null_mutex
>
stderr_sink_st
;
}
}
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#include <spdlog/details/null_mutex.h>
#include <cstdio>
#include <memory>
#include <mutex>
namespace
spdlog
{
namespace
sinks
{
template
<
class
Mutex
>
class
stdout_sink
:
public
base_sink
<
Mutex
>
{
using
MyType
=
stdout_sink
<
Mutex
>
;
public:
stdout_sink
()
{}
static
std
::
shared_ptr
<
MyType
>
instance
()
{
static
std
::
shared_ptr
<
MyType
>
instance
=
std
::
make_shared
<
MyType
>
();
return
instance
;
}
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
fwrite
(
msg
.
formatted
.
data
(),
sizeof
(
char
),
msg
.
formatted
.
size
(),
stdout
);
flush
();
}
void
flush
()
override
{
fflush
(
stdout
);
}
};
typedef
stdout_sink
<
details
::
null_mutex
>
stdout_sink_st
;
typedef
stdout_sink
<
std
::
mutex
>
stdout_sink_mt
;
template
<
class
Mutex
>
class
stderr_sink
:
public
base_sink
<
Mutex
>
{
using
MyType
=
stderr_sink
<
Mutex
>
;
public:
stderr_sink
()
{}
static
std
::
shared_ptr
<
MyType
>
instance
()
{
static
std
::
shared_ptr
<
MyType
>
instance
=
std
::
make_shared
<
MyType
>
();
return
instance
;
}
void
_sink_it
(
const
details
::
log_msg
&
msg
)
override
{
fwrite
(
msg
.
formatted
.
data
(),
sizeof
(
char
),
msg
.
formatted
.
size
(),
stderr
);
flush
();
}
void
flush
()
override
{
fflush
(
stderr
);
}
};
typedef
stderr_sink
<
std
::
mutex
>
stderr_sink_mt
;
typedef
stderr_sink
<
details
::
null_mutex
>
stderr_sink_st
;
}
}
include/spdlog/sinks/syslog_sink.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#if defined(__linux__) || defined(__APPLE__)
#include <spdlog/sinks/sink.h>
#include <spdlog/common.h>
#include <spdlog/details/log_msg.h>
#include <array>
#include <string>
#include <syslog.h>
namespace
spdlog
{
namespace
sinks
{
/**
* Sink that write to syslog using the `syscall()` library call.
*
* Locking is not needed, as `syslog()` itself is thread-safe.
*/
class
syslog_sink
:
public
sink
{
public:
//
syslog_sink
(
const
std
::
string
&
ident
=
""
,
int
syslog_option
=
0
,
int
syslog_facility
=
LOG_USER
)
:
_ident
(
ident
)
{
_priorities
[
static_cast
<
int
>
(
level
::
trace
)]
=
LOG_DEBUG
;
_priorities
[
static_cast
<
int
>
(
level
::
debug
)]
=
LOG_DEBUG
;
_priorities
[
static_cast
<
int
>
(
level
::
info
)]
=
LOG_INFO
;
_priorities
[
static_cast
<
int
>
(
level
::
notice
)]
=
LOG_NOTICE
;
_priorities
[
static_cast
<
int
>
(
level
::
warn
)]
=
LOG_WARNING
;
_priorities
[
static_cast
<
int
>
(
level
::
err
)]
=
LOG_ERR
;
_priorities
[
static_cast
<
int
>
(
level
::
critical
)]
=
LOG_CRIT
;
_priorities
[
static_cast
<
int
>
(
level
::
alert
)]
=
LOG_ALERT
;
_priorities
[
static_cast
<
int
>
(
level
::
emerg
)]
=
LOG_EMERG
;
_priorities
[
static_cast
<
int
>
(
level
::
off
)]
=
LOG_INFO
;
//set ident to be program name if empty
::
openlog
(
_ident
.
empty
()
?
nullptr
:
_ident
.
c_str
(),
syslog_option
,
syslog_facility
);
}
~
syslog_sink
()
{
::
closelog
();
}
syslog_sink
(
const
syslog_sink
&
)
=
delete
;
syslog_sink
&
operator
=
(
const
syslog_sink
&
)
=
delete
;
void
log
(
const
details
::
log_msg
&
msg
)
override
{
::
syslog
(
syslog_prio_from_level
(
msg
),
"%s"
,
msg
.
raw
.
str
().
c_str
());
}
void
flush
()
override
{
}
private:
std
::
array
<
int
,
10
>
_priorities
;
//must store the ident because the man says openlog might use the pointer as is and not a string copy
const
std
::
string
_ident
;
//
// Simply maps spdlog's log level to syslog priority level.
//
int
syslog_prio_from_level
(
const
details
::
log_msg
&
msg
)
const
{
return
_priorities
[
static_cast
<
int
>
(
msg
.
level
)];
}
};
}
}
#endif
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#pragma once
#if defined(__linux__) || defined(__APPLE__)
#include <spdlog/sinks/sink.h>
#include <spdlog/common.h>
#include <spdlog/details/log_msg.h>
#include <array>
#include <string>
#include <syslog.h>
namespace
spdlog
{
namespace
sinks
{
/**
* Sink that write to syslog using the `syscall()` library call.
*
* Locking is not needed, as `syslog()` itself is thread-safe.
*/
class
syslog_sink
:
public
sink
{
public:
//
syslog_sink
(
const
std
::
string
&
ident
=
""
,
int
syslog_option
=
0
,
int
syslog_facility
=
LOG_USER
)
:
_ident
(
ident
)
{
_priorities
[
static_cast
<
int
>
(
level
::
trace
)]
=
LOG_DEBUG
;
_priorities
[
static_cast
<
int
>
(
level
::
debug
)]
=
LOG_DEBUG
;
_priorities
[
static_cast
<
int
>
(
level
::
info
)]
=
LOG_INFO
;
_priorities
[
static_cast
<
int
>
(
level
::
notice
)]
=
LOG_NOTICE
;
_priorities
[
static_cast
<
int
>
(
level
::
warn
)]
=
LOG_WARNING
;
_priorities
[
static_cast
<
int
>
(
level
::
err
)]
=
LOG_ERR
;
_priorities
[
static_cast
<
int
>
(
level
::
critical
)]
=
LOG_CRIT
;
_priorities
[
static_cast
<
int
>
(
level
::
alert
)]
=
LOG_ALERT
;
_priorities
[
static_cast
<
int
>
(
level
::
emerg
)]
=
LOG_EMERG
;
_priorities
[
static_cast
<
int
>
(
level
::
off
)]
=
LOG_INFO
;
//set ident to be program name if empty
::
openlog
(
_ident
.
empty
()
?
nullptr
:
_ident
.
c_str
(),
syslog_option
,
syslog_facility
);
}
~
syslog_sink
()
{
::
closelog
();
}
syslog_sink
(
const
syslog_sink
&
)
=
delete
;
syslog_sink
&
operator
=
(
const
syslog_sink
&
)
=
delete
;
void
log
(
const
details
::
log_msg
&
msg
)
override
{
::
syslog
(
syslog_prio_from_level
(
msg
),
"%s"
,
msg
.
raw
.
str
().
c_str
());
}
void
flush
()
override
{
}
private:
std
::
array
<
int
,
10
>
_priorities
;
//must store the ident because the man says openlog might use the pointer as is and not a string copy
const
std
::
string
_ident
;
//
// Simply maps spdlog's log level to syslog priority level.
//
int
syslog_prio_from_level
(
const
details
::
log_msg
&
msg
)
const
{
return
_priorities
[
static_cast
<
int
>
(
msg
.
level
)];
}
};
}
}
#endif
include/spdlog/spdlog.h
View file @
0d263598
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
// spdlog main header file.
// see example.cpp for usage example
#pragma once
#include <spdlog/tweakme.h>
#include <spdlog/common.h>
#include <spdlog/logger.h>
#include <memory>
#include <functional>
#include <chrono>
#include <string>
namespace
spdlog
{
// Return an existing logger or nullptr if a logger with such name doesn't exist.
// Examples:
//
// spdlog::get("mylog")->info("Hello");
// auto logger = spdlog::get("mylog");
// logger.info("This is another message" , x, y, z);
// logger.info() << "This is another message" << x << y << z;
std
::
shared_ptr
<
logger
>
get
(
const
std
::
string
&
name
);
//
// Set global formatting
// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v");
//
void
set_pattern
(
const
std
::
string
&
format_string
);
void
set_formatter
(
formatter_ptr
f
);
//
// Set global logging level for
//
void
set_level
(
level
::
level_enum
log_level
);
//
// Turn on async mode (off by default) and set the queue size for each async_logger.
// effective only for loggers created after this call.
// queue_size: size of queue (must be power of 2):
// Each logger will pre-allocate a dedicated queue with queue_size entries upon construction.
//
// async_overflow_policy (optional, block_retry by default):
// async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry.
// async_overflow_policy::discard_log_msg - never block and discard any new messages when queue overflows.
//
// worker_warmup_cb (optional):
// callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity)
//
void
set_async_mode
(
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
=
async_overflow_policy
::
block_retry
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
=
nullptr
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
=
std
::
chrono
::
milliseconds
::
zero
());
// Turn off async mode
void
set_sync_mode
();
//
// Create and register multi/single threaded rotating file logger
//
std
::
shared_ptr
<
logger
>
rotating_logger_mt
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
size_t
max_file_size
,
size_t
max_files
,
bool
force_flush
=
false
);
std
::
shared_ptr
<
logger
>
rotating_logger_st
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
size_t
max_file_size
,
size_t
max_files
,
bool
force_flush
=
false
);
//
// Create file logger which creates new file on the given time (default in midnight):
//
std
::
shared_ptr
<
logger
>
daily_logger_mt
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
int
hour
=
0
,
int
minute
=
0
,
bool
force_flush
=
false
);
std
::
shared_ptr
<
logger
>
daily_logger_st
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
int
hour
=
0
,
int
minute
=
0
,
bool
force_flush
=
false
);
//
// Create and register stdout/stderr loggers
//
std
::
shared_ptr
<
logger
>
stdout_logger_mt
(
const
std
::
string
&
logger_name
,
bool
color
=
false
);
std
::
shared_ptr
<
logger
>
stdout_logger_st
(
const
std
::
string
&
logger_name
,
bool
color
=
false
);
std
::
shared_ptr
<
logger
>
stderr_logger_mt
(
const
std
::
string
&
logger_name
,
bool
color
=
false
);
std
::
shared_ptr
<
logger
>
stderr_logger_st
(
const
std
::
string
&
logger_name
,
bool
color
=
false
);
//
// Create and register a syslog logger
//
#if defined(__linux__) || defined(__APPLE__)
std
::
shared_ptr
<
logger
>
syslog_logger
(
const
std
::
string
&
logger_name
,
const
std
::
string
&
ident
=
""
,
int
syslog_option
=
0
);
#endif
// Create and register a logger with multiple sinks
std
::
shared_ptr
<
logger
>
create
(
const
std
::
string
&
logger_name
,
sinks_init_list
sinks
);
template
<
class
It
>
std
::
shared_ptr
<
logger
>
create
(
const
std
::
string
&
logger_name
,
const
It
&
sinks_begin
,
const
It
&
sinks_end
);
// Create and register a logger with templated sink type
// Example: spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename", "txt");
template
<
typename
Sink
,
typename
...
Args
>
std
::
shared_ptr
<
spdlog
::
logger
>
create
(
const
std
::
string
&
logger_name
,
Args
...);
// Register the given logger with the given name
void
register_logger
(
std
::
shared_ptr
<
logger
>
logger
);
// Drop the reference to the given logger
void
drop
(
const
std
::
string
&
name
);
// Drop all references
void
drop_all
();
///////////////////////////////////////////////////////////////////////////////
//
// Macros to be display source file & line
// Trace & Debug can be switched on/off at compile time for zero cost debug statements.
// Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in teakme.h to enable.
//
// Example:
// spdlog::set_level(spdlog::level::debug);
// SPDLOG_DEBUG(my_logger, "Some debug message {} {}", 1, 3.2);
///////////////////////////////////////////////////////////////////////////////
#ifdef SPDLOG_TRACE_ON
#define SPDLOG_TRACE(logger, ...) logger->trace(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
#else
#define SPDLOG_TRACE(logger, ...)
#endif
#ifdef SPDLOG_DEBUG_ON
#define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
#else
#define SPDLOG_DEBUG(logger, ...)
#endif
}
#include <spdlog/details/spdlog_impl.h>
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
// spdlog main header file.
// see example.cpp for usage example
#pragma once
#include <spdlog/tweakme.h>
#include <spdlog/common.h>
#include <spdlog/logger.h>
#include <memory>
#include <functional>
#include <chrono>
#include <string>
namespace
spdlog
{
// Return an existing logger or nullptr if a logger with such name doesn't exist.
// Examples:
//
// spdlog::get("mylog")->info("Hello");
// auto logger = spdlog::get("mylog");
// logger.info("This is another message" , x, y, z);
// logger.info() << "This is another message" << x << y << z;
std
::
shared_ptr
<
logger
>
get
(
const
std
::
string
&
name
);
//
// Set global formatting
// example: spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l : %v");
//
void
set_pattern
(
const
std
::
string
&
format_string
);
void
set_formatter
(
formatter_ptr
f
);
//
// Set global logging level for
//
void
set_level
(
level
::
level_enum
log_level
);
//
// Turn on async mode (off by default) and set the queue size for each async_logger.
// effective only for loggers created after this call.
// queue_size: size of queue (must be power of 2):
// Each logger will pre-allocate a dedicated queue with queue_size entries upon construction.
//
// async_overflow_policy (optional, block_retry by default):
// async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry.
// async_overflow_policy::discard_log_msg - never block and discard any new messages when queue overflows.
//
// worker_warmup_cb (optional):
// callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity)
//
void
set_async_mode
(
size_t
queue_size
,
const
async_overflow_policy
overflow_policy
=
async_overflow_policy
::
block_retry
,
const
std
::
function
<
void
()
>&
worker_warmup_cb
=
nullptr
,
const
std
::
chrono
::
milliseconds
&
flush_interval_ms
=
std
::
chrono
::
milliseconds
::
zero
());
// Turn off async mode
void
set_sync_mode
();
//
// Create and register multi/single threaded rotating file logger
//
std
::
shared_ptr
<
logger
>
rotating_logger_mt
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
size_t
max_file_size
,
size_t
max_files
,
bool
force_flush
=
false
);
std
::
shared_ptr
<
logger
>
rotating_logger_st
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
size_t
max_file_size
,
size_t
max_files
,
bool
force_flush
=
false
);
//
// Create file logger which creates new file on the given time (default in midnight):
//
std
::
shared_ptr
<
logger
>
daily_logger_mt
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
int
hour
=
0
,
int
minute
=
0
,
bool
force_flush
=
false
);
std
::
shared_ptr
<
logger
>
daily_logger_st
(
const
std
::
string
&
logger_name
,
const
filename_t
&
filename
,
int
hour
=
0
,
int
minute
=
0
,
bool
force_flush
=
false
);
//
// Create and register stdout/stderr loggers
//
std
::
shared_ptr
<
logger
>
stdout_logger_mt
(
const
std
::
string
&
logger_name
,
bool
color
=
false
);
std
::
shared_ptr
<
logger
>
stdout_logger_st
(
const
std
::
string
&
logger_name
,
bool
color
=
false
);
std
::
shared_ptr
<
logger
>
stderr_logger_mt
(
const
std
::
string
&
logger_name
,
bool
color
=
false
);
std
::
shared_ptr
<
logger
>
stderr_logger_st
(
const
std
::
string
&
logger_name
,
bool
color
=
false
);
//
// Create and register a syslog logger
//
#if defined(__linux__) || defined(__APPLE__)
std
::
shared_ptr
<
logger
>
syslog_logger
(
const
std
::
string
&
logger_name
,
const
std
::
string
&
ident
=
""
,
int
syslog_option
=
0
);
#endif
// Create and register a logger with multiple sinks
std
::
shared_ptr
<
logger
>
create
(
const
std
::
string
&
logger_name
,
sinks_init_list
sinks
);
template
<
class
It
>
std
::
shared_ptr
<
logger
>
create
(
const
std
::
string
&
logger_name
,
const
It
&
sinks_begin
,
const
It
&
sinks_end
);
// Create and register a logger with templated sink type
// Example: spdlog::create<daily_file_sink_st>("mylog", "dailylog_filename", "txt");
template
<
typename
Sink
,
typename
...
Args
>
std
::
shared_ptr
<
spdlog
::
logger
>
create
(
const
std
::
string
&
logger_name
,
Args
...);
// Register the given logger with the given name
void
register_logger
(
std
::
shared_ptr
<
logger
>
logger
);
// Drop the reference to the given logger
void
drop
(
const
std
::
string
&
name
);
// Drop all references
void
drop_all
();
///////////////////////////////////////////////////////////////////////////////
//
// Macros to be display source file & line
// Trace & Debug can be switched on/off at compile time for zero cost debug statements.
// Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in teakme.h to enable.
//
// Example:
// spdlog::set_level(spdlog::level::debug);
// SPDLOG_DEBUG(my_logger, "Some debug message {} {}", 1, 3.2);
///////////////////////////////////////////////////////////////////////////////
#ifdef SPDLOG_TRACE_ON
#define SPDLOG_TRACE(logger, ...) logger->trace(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
#else
#define SPDLOG_TRACE(logger, ...)
#endif
#ifdef SPDLOG_DEBUG_ON
#define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__) << " (" << __FILE__ << " #" << __LINE__ <<")";
#else
#define SPDLOG_DEBUG(logger, ...)
#endif
}
#include <spdlog/details/spdlog_impl.h>
tests/file_helper.cpp
View file @
0d263598
/*
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
*/
#include "includes.h"
using
namespace
spdlog
::
details
;
static
const
std
::
string
target_filename
=
"logs/file_helper_test.txt"
;
static
void
write_with_helper
(
file_helper
&
helper
,
size_t
howmany
)
{
log_msg
msg
;
msg
.
formatted
<<
std
::
string
(
howmany
,
'1'
);
helper
.
write
(
msg
);
}
TEST_CASE
(
"file_helper_filename"
,
"[file_helper::filename()]]"
)
{
prepare_logdir
();
file_helper
helper
(
false
);
helper
.
open
(
target_filename
);
REQUIRE
(
helper
.
filename
()
==
target_filename
);
}
TEST_CASE
(
"file_helper_size"
,
"[file_helper::size()]]"
)
{
prepare_logdir
();
auto
expected_size
=
123
;
{
file_helper
helper
(
true
);
helper
.
open
(
target_filename
);
write_with_helper
(
helper
,
expected_size
);
REQUIRE
(
helper
.
size
()
==
expected_size
);
}
REQUIRE
(
get_filesize
(
target_filename
)
==
expected_size
);
}
TEST_CASE
(
"file_helper_exists"
,
"[file_helper::file_exists()]]"
)
{
prepare_logdir
();
REQUIRE
(
!
file_helper
::
file_exists
(
target_filename
));
file_helper
helper
(
false
);
helper
.
open
(
target_filename
);
REQUIRE
(
file_helper
::
file_exists
(
target_filename
));
}
TEST_CASE
(
"file_helper_reopen"
,
"[file_helper::reopen()]]"
)
{
prepare_logdir
();
file_helper
helper
(
true
);
helper
.
open
(
target_filename
);
write_with_helper
(
helper
,
12
);
REQUIRE
(
helper
.
size
()
==
12
);
helper
.
reopen
(
true
);
REQUIRE
(
helper
.
size
()
==
0
);
}
TEST_CASE
(
"file_helper_reopen2"
,
"[file_helper::reopen(false)]]"
)
{
prepare_logdir
();
auto
expected_size
=
14
;
file_helper
helper
(
true
);
helper
.
open
(
target_filename
);
write_with_helper
(
helper
,
expected_size
);
REQUIRE
(
helper
.
size
()
==
expected_size
);
helper
.
reopen
(
false
);
REQUIRE
(
helper
.
size
()
==
expected_size
);
}
/*
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
*/
#include "includes.h"
using
namespace
spdlog
::
details
;
static
const
std
::
string
target_filename
=
"logs/file_helper_test.txt"
;
static
void
write_with_helper
(
file_helper
&
helper
,
size_t
howmany
)
{
log_msg
msg
;
msg
.
formatted
<<
std
::
string
(
howmany
,
'1'
);
helper
.
write
(
msg
);
}
TEST_CASE
(
"file_helper_filename"
,
"[file_helper::filename()]]"
)
{
prepare_logdir
();
file_helper
helper
(
false
);
helper
.
open
(
target_filename
);
REQUIRE
(
helper
.
filename
()
==
target_filename
);
}
TEST_CASE
(
"file_helper_size"
,
"[file_helper::size()]]"
)
{
prepare_logdir
();
auto
expected_size
=
123
;
{
file_helper
helper
(
true
);
helper
.
open
(
target_filename
);
write_with_helper
(
helper
,
expected_size
);
REQUIRE
(
helper
.
size
()
==
expected_size
);
}
REQUIRE
(
get_filesize
(
target_filename
)
==
expected_size
);
}
TEST_CASE
(
"file_helper_exists"
,
"[file_helper::file_exists()]]"
)
{
prepare_logdir
();
REQUIRE
(
!
file_helper
::
file_exists
(
target_filename
));
file_helper
helper
(
false
);
helper
.
open
(
target_filename
);
REQUIRE
(
file_helper
::
file_exists
(
target_filename
));
}
TEST_CASE
(
"file_helper_reopen"
,
"[file_helper::reopen()]]"
)
{
prepare_logdir
();
file_helper
helper
(
true
);
helper
.
open
(
target_filename
);
write_with_helper
(
helper
,
12
);
REQUIRE
(
helper
.
size
()
==
12
);
helper
.
reopen
(
true
);
REQUIRE
(
helper
.
size
()
==
0
);
}
TEST_CASE
(
"file_helper_reopen2"
,
"[file_helper::reopen(false)]]"
)
{
prepare_logdir
();
auto
expected_size
=
14
;
file_helper
helper
(
true
);
helper
.
open
(
target_filename
);
write_with_helper
(
helper
,
expected_size
);
REQUIRE
(
helper
.
size
()
==
expected_size
);
helper
.
reopen
(
false
);
REQUIRE
(
helper
.
size
()
==
expected_size
);
}
tests/file_log.cpp
View file @
0d263598
/*
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
*/
#include "includes.h"
TEST_CASE
(
"simple_file_logger"
,
"[simple_logger]]"
)
{
prepare_logdir
();
std
::
string
filename
=
"logs/simple_log.txt"
;
auto
logger
=
spdlog
::
create
<
spdlog
::
sinks
::
simple_file_sink_mt
>
(
"logger"
,
filename
);
logger
->
set_pattern
(
"%v"
);
logger
->
info
(
"Test message {}"
,
1
);
logger
->
info
(
"Test message {}"
,
2
);
logger
->
flush
();
REQUIRE
(
file_contents
(
filename
)
==
std
::
string
(
"Test message 1
\n
Test message 2
\n
"
));
REQUIRE
(
count_lines
(
filename
)
==
2
);
}
TEST_CASE
(
"rotating_file_logger1"
,
"[rotating_logger]]"
)
{
prepare_logdir
();
std
::
string
basename
=
"logs/rotating_log"
;
auto
logger
=
spdlog
::
rotating_logger_mt
(
"logger"
,
basename
,
1024
,
0
,
true
);
for
(
int
i
=
0
;
i
<
10
;
++
i
)
logger
->
info
(
"Test message {}"
,
i
);
auto
filename
=
basename
+
".txt"
;
REQUIRE
(
count_lines
(
filename
)
==
10
);
for
(
int
i
=
0
;
i
<
1000
;
i
++
)
logger
->
info
(
"Test message {}"
,
i
);
}
TEST_CASE
(
"rotating_file_logger2"
,
"[rotating_logger]]"
)
{
prepare_logdir
();
std
::
string
basename
=
"logs/rotating_log"
;
auto
logger
=
spdlog
::
rotating_logger_mt
(
"logger"
,
basename
,
1024
,
1
,
false
);
for
(
int
i
=
0
;
i
<
10
;
++
i
)
logger
->
info
(
"Test message {}"
,
i
);
logger
->
flush
();
auto
filename
=
basename
+
".txt"
;
REQUIRE
(
count_lines
(
filename
)
==
10
);
for
(
int
i
=
0
;
i
<
1000
;
i
++
)
logger
->
info
(
"Test message {}"
,
i
);
logger
->
flush
();
REQUIRE
(
get_filesize
(
filename
)
<=
1024
);
auto
filename1
=
basename
+
".1.txt"
;
REQUIRE
(
get_filesize
(
filename1
)
<=
1024
);
}
TEST_CASE
(
"daily_logger"
,
"[daily_logger]]"
)
{
prepare_logdir
();
//calculate filename (time based)
std
::
string
basename
=
"logs/daily_log"
;
std
::
tm
tm
=
spdlog
::
details
::
os
::
localtime
();
fmt
::
MemoryWriter
w
;
w
.
write
(
"{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.txt"
,
basename
,
tm
.
tm_year
+
1900
,
tm
.
tm_mon
+
1
,
tm
.
tm_mday
,
tm
.
tm_hour
,
tm
.
tm_min
);
auto
logger
=
spdlog
::
daily_logger_mt
(
"logger"
,
basename
,
0
,
0
,
true
);
for
(
int
i
=
0
;
i
<
10
;
++
i
)
logger
->
info
(
"Test message {}"
,
i
);
auto
filename
=
w
.
str
();
REQUIRE
(
count_lines
(
filename
)
==
10
);
}
/*
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
*/
#include "includes.h"
TEST_CASE
(
"simple_file_logger"
,
"[simple_logger]]"
)
{
prepare_logdir
();
std
::
string
filename
=
"logs/simple_log.txt"
;
auto
logger
=
spdlog
::
create
<
spdlog
::
sinks
::
simple_file_sink_mt
>
(
"logger"
,
filename
);
logger
->
set_pattern
(
"%v"
);
logger
->
info
(
"Test message {}"
,
1
);
logger
->
info
(
"Test message {}"
,
2
);
logger
->
flush
();
REQUIRE
(
file_contents
(
filename
)
==
std
::
string
(
"Test message 1
\n
Test message 2
\n
"
));
REQUIRE
(
count_lines
(
filename
)
==
2
);
}
TEST_CASE
(
"rotating_file_logger1"
,
"[rotating_logger]]"
)
{
prepare_logdir
();
std
::
string
basename
=
"logs/rotating_log"
;
auto
logger
=
spdlog
::
rotating_logger_mt
(
"logger"
,
basename
,
1024
,
0
,
true
);
for
(
int
i
=
0
;
i
<
10
;
++
i
)
logger
->
info
(
"Test message {}"
,
i
);
auto
filename
=
basename
+
".txt"
;
REQUIRE
(
count_lines
(
filename
)
==
10
);
for
(
int
i
=
0
;
i
<
1000
;
i
++
)
logger
->
info
(
"Test message {}"
,
i
);
}
TEST_CASE
(
"rotating_file_logger2"
,
"[rotating_logger]]"
)
{
prepare_logdir
();
std
::
string
basename
=
"logs/rotating_log"
;
auto
logger
=
spdlog
::
rotating_logger_mt
(
"logger"
,
basename
,
1024
,
1
,
false
);
for
(
int
i
=
0
;
i
<
10
;
++
i
)
logger
->
info
(
"Test message {}"
,
i
);
logger
->
flush
();
auto
filename
=
basename
+
".txt"
;
REQUIRE
(
count_lines
(
filename
)
==
10
);
for
(
int
i
=
0
;
i
<
1000
;
i
++
)
logger
->
info
(
"Test message {}"
,
i
);
logger
->
flush
();
REQUIRE
(
get_filesize
(
filename
)
<=
1024
);
auto
filename1
=
basename
+
".1.txt"
;
REQUIRE
(
get_filesize
(
filename1
)
<=
1024
);
}
TEST_CASE
(
"daily_logger"
,
"[daily_logger]]"
)
{
prepare_logdir
();
//calculate filename (time based)
std
::
string
basename
=
"logs/daily_log"
;
std
::
tm
tm
=
spdlog
::
details
::
os
::
localtime
();
fmt
::
MemoryWriter
w
;
w
.
write
(
"{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.txt"
,
basename
,
tm
.
tm_year
+
1900
,
tm
.
tm_mon
+
1
,
tm
.
tm_mday
,
tm
.
tm_hour
,
tm
.
tm_min
);
auto
logger
=
spdlog
::
daily_logger_mt
(
"logger"
,
basename
,
0
,
0
,
true
);
for
(
int
i
=
0
;
i
<
10
;
++
i
)
logger
->
info
(
"Test message {}"
,
i
);
auto
filename
=
w
.
str
();
REQUIRE
(
count_lines
(
filename
)
==
10
);
}
tests/includes.h
View file @
0d263598
#pragma once
#include <cstdio>
#include <fstream>
#include <string>
#include <ostream>
#include <chrono>
#include <exception>
#include "catch.hpp"
#include "utils.h"
#include "../include/spdlog/spdlog.h"
#include "../include/spdlog/sinks/null_sink.h"
#include "../include/spdlog/sinks/ostream_sink.h"
#pragma once
#include <cstdio>
#include <fstream>
#include <string>
#include <ostream>
#include <chrono>
#include <exception>
#include "catch.hpp"
#include "utils.h"
#include "../include/spdlog/spdlog.h"
#include "../include/spdlog/sinks/null_sink.h"
#include "../include/spdlog/sinks/ostream_sink.h"
tests/utils.cpp
View file @
0d263598
#include "includes.h"
void
prepare_logdir
()
{
spdlog
::
drop_all
();
#ifdef _WIN32
auto
rv
=
system
(
"del /F /Q logs
\\
*"
);
#else
auto
rv
=
system
(
"rm -f logs/*"
);
#endif
(
void
)
rv
;
}
std
::
string
file_contents
(
const
std
::
string
&
filename
)
{
std
::
ifstream
ifs
(
filename
);
if
(
!
ifs
)
throw
std
::
runtime_error
(
"Failed open file "
);
return
std
::
string
((
std
::
istreambuf_iterator
<
char
>
(
ifs
)),
(
std
::
istreambuf_iterator
<
char
>
()));
}
std
::
size_t
count_lines
(
const
std
::
string
&
filename
)
{
std
::
ifstream
ifs
(
filename
);
if
(
!
ifs
)
throw
std
::
runtime_error
(
"Failed open file "
);
std
::
string
line
;
size_t
counter
=
0
;
while
(
std
::
getline
(
ifs
,
line
))
counter
++
;
return
counter
;
}
std
::
size_t
get_filesize
(
const
std
::
string
&
filename
)
{
std
::
ifstream
ifs
(
filename
,
std
::
ifstream
::
ate
|
std
::
ifstream
::
binary
);
if
(
!
ifs
)
throw
std
::
runtime_error
(
"Failed open file "
);
return
ifs
.
tellg
();
}
#include "includes.h"
void
prepare_logdir
()
{
spdlog
::
drop_all
();
#ifdef _WIN32
auto
rv
=
system
(
"del /F /Q logs
\\
*"
);
#else
auto
rv
=
system
(
"rm -f logs/*"
);
#endif
(
void
)
rv
;
}
std
::
string
file_contents
(
const
std
::
string
&
filename
)
{
std
::
ifstream
ifs
(
filename
);
if
(
!
ifs
)
throw
std
::
runtime_error
(
"Failed open file "
);
return
std
::
string
((
std
::
istreambuf_iterator
<
char
>
(
ifs
)),
(
std
::
istreambuf_iterator
<
char
>
()));
}
std
::
size_t
count_lines
(
const
std
::
string
&
filename
)
{
std
::
ifstream
ifs
(
filename
);
if
(
!
ifs
)
throw
std
::
runtime_error
(
"Failed open file "
);
std
::
string
line
;
size_t
counter
=
0
;
while
(
std
::
getline
(
ifs
,
line
))
counter
++
;
return
counter
;
}
std
::
size_t
get_filesize
(
const
std
::
string
&
filename
)
{
std
::
ifstream
ifs
(
filename
,
std
::
ifstream
::
ate
|
std
::
ifstream
::
binary
);
if
(
!
ifs
)
throw
std
::
runtime_error
(
"Failed open file "
);
return
ifs
.
tellg
();
}
tests/utils.h
View file @
0d263598
#pragma once
#include <string>
#include<cstddef>
std
::
size_t
count_lines
(
const
std
::
string
&
filename
);
void
prepare_logdir
();
std
::
string
file_contents
(
const
std
::
string
&
filename
);
std
::
size_t
count_lines
(
const
std
::
string
&
filename
);
std
::
size_t
get_filesize
(
const
std
::
string
&
filename
);
#pragma once
#include <string>
#include<cstddef>
std
::
size_t
count_lines
(
const
std
::
string
&
filename
);
void
prepare_logdir
();
std
::
string
file_contents
(
const
std
::
string
&
filename
);
std
::
size_t
count_lines
(
const
std
::
string
&
filename
);
std
::
size_t
get_filesize
(
const
std
::
string
&
filename
);
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