Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
S
spdlog
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
spdlog
Commits
17f9cdd4
Commit
17f9cdd4
authored
Apr 05, 2019
by
gabime
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
static lib wip
parent
156b856a
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1351 additions
and
1358 deletions
+1351
-1358
example.cpp
example/example.cpp
+4
-2
common.h
include/spdlog/common.h
+11
-7
async_logger_impl.h
include/spdlog/details/async_logger_impl.h
+1
-4
pattern_formatter.h
include/spdlog/details/pattern_formatter.h
+31
-1263
registry.h
include/spdlog/details/registry.h
+2
-2
logger.h
include/spdlog/logger.h
+7
-16
spdlog.h
include/spdlog/spdlog.h
+2
-2
tweakme.h
include/spdlog/tweakme.h
+0
-7
logger.cpp
src/logger.cpp
+12
-23
os.cpp
src/os.cpp
+0
-2
pattern_formatter.cpp
src/pattern_formatter.cpp
+1266
-0
includes.h
tests/includes.h
+0
-1
test_errors.cpp
tests/test_errors.cpp
+15
-11
test_misc.cpp
tests/test_misc.cpp
+0
-18
No files found.
example/example.cpp
View file @
17f9cdd4
...
...
@@ -14,8 +14,9 @@ spdlog::logger *get_logger();
int
main
(
int
,
char
*
[])
{
auto
*
l
=
get_logger
();
l
->
info
(
"HELLO {}"
,
"GA"
);
l
->
error
(
"Some {}"
,
"error"
);
l
->
info
(
"HE LO "
,
"GA"
);
l
->
error
(
"Some {} {} {}"
,
"er or"
);
l
->
error
(
"Some {} {} {}"
,
"er or"
);
}
\ No newline at end of file
include/spdlog/common.h
View file @
17f9cdd4
...
...
@@ -9,22 +9,16 @@
#include <atomic>
#include <chrono>
#include <functional>
#include <initializer_list>
#include <memory>
#include <stdexcept>
#include <string>
#include <cstring>
#include <type_traits>
#include <unordered_map>
#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
#include <codecvt>
#include <locale>
#endif
#include "spdlog/details/null_mutex.h"
#include "spdlog/fmt/fmt.h"
#ifdef SPDLOG_HEADER_ONLY
...
...
@@ -75,6 +69,17 @@
#define SPDLOG_FUNCTION __FUNCTION__
#endif
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
#define SPDLOG_FILENAME_T(s) L##s
SPDLOG_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
#endif
namespace
spdlog
{
class
formatter
;
...
...
@@ -86,7 +91,6 @@ class sink;
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
log_err_handler
=
std
::
function
<
void
(
const
std
::
string
&
err_msg
)
>
;
// string_view type - either std::string_view or fmt::string_view (pre c++17)
#if defined(FMT_USE_STD_STRING_VIEW)
...
...
include/spdlog/details/async_logger_impl.h
View file @
17f9cdd4
...
...
@@ -38,9 +38,6 @@ inline spdlog::async_logger::async_logger(
// send the log message to the thread pool
inline
void
spdlog
::
async_logger
::
sink_it_
(
details
::
log_msg
&
msg
)
{
#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)
incr_msg_counter_
(
msg
);
#endif
if
(
auto
pool_ptr
=
thread_pool_
.
lock
())
{
pool_ptr
->
post_log
(
shared_from_this
(),
msg
,
overflow_policy_
);
...
...
@@ -119,6 +116,6 @@ inline std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string n
cloned
->
set_level
(
this
->
level
());
cloned
->
flush_on
(
this
->
flush_level
());
cloned
->
set_error_handler
(
this
->
error_handler
()
);
cloned
->
set_error_handler
(
this
->
custom_err_handler_
);
return
std
::
move
(
cloned
);
}
include/spdlog/details/pattern_formatter.h
View file @
17f9cdd4
...
...
@@ -4,26 +4,23 @@
//
#pragma once
#include "spdlog/
details/fmt_helper
.h"
#include "spdlog/
common
.h"
#include "spdlog/details/log_msg.h"
#include "spdlog/details/os.h"
#include "spdlog/fmt/fmt.h"
#include "spdlog/formatter.h"
#include <array>
#include <chrono>
#include <ctime>
#include <cctype>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <utility>
#include <vector>
namespace
spdlog
{
namespace
details
{
// padding information.
struct
padding_info
{
...
...
@@ -49,64 +46,6 @@ struct padding_info
const
pad_side
side_
=
left
;
};
class
scoped_pad
{
public
:
scoped_pad
(
size_t
wrapped_size
,
padding_info
&
padinfo
,
fmt
::
memory_buffer
&
dest
)
:
padinfo_
(
padinfo
)
,
dest_
(
dest
)
{
if
(
padinfo_
.
width_
<=
wrapped_size
)
{
total_pad_
=
0
;
return
;
}
total_pad_
=
padinfo
.
width_
-
wrapped_size
;
if
(
padinfo_
.
side_
==
padding_info
::
left
)
{
pad_it
(
total_pad_
);
total_pad_
=
0
;
}
else
if
(
padinfo_
.
side_
==
padding_info
::
center
)
{
auto
half_pad
=
total_pad_
/
2
;
auto
reminder
=
total_pad_
&
1
;
pad_it
(
half_pad
);
total_pad_
=
half_pad
+
reminder
;
// for the right side
}
}
scoped_pad
(
spdlog
::
string_view_t
txt
,
padding_info
&
padinfo
,
fmt
::
memory_buffer
&
dest
)
:
scoped_pad
(
txt
.
size
(),
padinfo
,
dest
)
{
}
~
scoped_pad
()
{
if
(
total_pad_
)
{
pad_it
(
total_pad_
);
}
}
private
:
void
pad_it
(
size_t
count
)
{
// count = std::min(count, spaces_.size());
assert
(
count
<=
spaces_
.
size
());
fmt_helper
::
append_string_view
(
string_view_t
(
spaces_
.
data
(),
count
),
dest_
);
}
const
padding_info
&
padinfo_
;
fmt
::
memory_buffer
&
dest_
;
size_t
total_pad_
;
string_view_t
spaces_
{
" "
" "
,
128
};
};
class
flag_formatter
{
public
:
...
...
@@ -122,1218 +61,47 @@ protected:
padding_info
padinfo_
;
};
///////////////////////////////////////////////////////////////////////
// name & level pattern appender
///////////////////////////////////////////////////////////////////////
class
name_formatter
:
public
flag_formatter
{
public
:
explicit
name_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
padinfo_
.
enabled
())
{
scoped_pad
p
(
*
msg
.
logger_name
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
*
msg
.
logger_name
,
dest
);
}
else
{
fmt_helper
::
append_string_view
(
*
msg
.
logger_name
,
dest
);
}
}
};
// log level appender
class
level_formatter
:
public
flag_formatter
{
public
:
explicit
level_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
string_view_t
&
level_name
=
level
::
to_string_view
(
msg
.
level
);
if
(
padinfo_
.
enabled
())
{
scoped_pad
p
(
level_name
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
level_name
,
dest
);
}
else
{
fmt_helper
::
append_string_view
(
level_name
,
dest
);
}
}
};
// short log level appender
class
short_level_formatter
:
public
flag_formatter
{
public
:
explicit
short_level_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
string_view_t
level_name
{
level
::
to_short_c_str
(
msg
.
level
)};
scoped_pad
p
(
level_name
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
level_name
,
dest
);
}
};
///////////////////////////////////////////////////////////////////////
// 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
char
*
days
[]{
"Sun"
,
"Mon"
,
"Tue"
,
"Wed"
,
"Thu"
,
"Fri"
,
"Sat"
};
class
a_formatter
:
public
flag_formatter
{
public
:
explicit
a_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
string_view_t
field_value
{
days
[
tm_time
.
tm_wday
]};
scoped_pad
p
(
field_value
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
field_value
,
dest
);
}
};
// Full weekday name
static
const
char
*
full_days
[]{
"Sunday"
,
"Monday"
,
"Tuesday"
,
"Wednesday"
,
"Thursday"
,
"Friday"
,
"Saturday"
};
class
A_formatter
:
public
flag_formatter
{
public
:
explicit
A_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
string_view_t
field_value
{
full_days
[
tm_time
.
tm_wday
]};
scoped_pad
p
(
field_value
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
field_value
,
dest
);
}
};
// Abbreviated month
static
const
char
*
months
[]{
"Jan"
,
"Feb"
,
"Mar"
,
"Apr"
,
"May"
,
"Jun"
,
"Jul"
,
"Aug"
,
"Sept"
,
"Oct"
,
"Nov"
,
"Dec"
};
class
b_formatter
:
public
flag_formatter
{
public
:
explicit
b_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
string_view_t
field_value
{
months
[
tm_time
.
tm_mon
]};
scoped_pad
p
(
field_value
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
field_value
,
dest
);
}
};
// Full month name
static
const
char
*
full_months
[]{
"January"
,
"February"
,
"March"
,
"April"
,
"May"
,
"June"
,
"July"
,
"August"
,
"September"
,
"October"
,
"November"
,
"December"
};
class
B_formatter
:
public
flag_formatter
{
public
:
explicit
B_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
string_view_t
field_value
{
full_months
[
tm_time
.
tm_mon
]};
scoped_pad
p
(
field_value
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
field_value
,
dest
);
}
};
// Date and time representation (Thu Aug 23 15:35:46 2014)
class
c_formatter
final
:
public
flag_formatter
{
public
:
explicit
c_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
24
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
days
[
tm_time
.
tm_wday
],
dest
);
dest
.
push_back
(
' '
);
fmt_helper
::
append_string_view
(
months
[
tm_time
.
tm_mon
],
dest
);
dest
.
push_back
(
' '
);
fmt_helper
::
append_int
(
tm_time
.
tm_mday
,
dest
);
dest
.
push_back
(
' '
);
// time
fmt_helper
::
pad2
(
tm_time
.
tm_hour
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_min
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_sec
,
dest
);
dest
.
push_back
(
' '
);
fmt_helper
::
append_int
(
tm_time
.
tm_year
+
1900
,
dest
);
}
};
// year - 2 digit
class
C_formatter
final
:
public
flag_formatter
{
public
:
explicit
C_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_year
%
100
,
dest
);
}
};
// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01
class
D_formatter
final
:
public
flag_formatter
{
public
:
explicit
D_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
10
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_mon
+
1
,
dest
);
dest
.
push_back
(
'/'
);
fmt_helper
::
pad2
(
tm_time
.
tm_mday
,
dest
);
dest
.
push_back
(
'/'
);
fmt_helper
::
pad2
(
tm_time
.
tm_year
%
100
,
dest
);
}
};
// year - 4 digit
class
Y_formatter
final
:
public
flag_formatter
{
public
:
explicit
Y_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
4
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
append_int
(
tm_time
.
tm_year
+
1900
,
dest
);
}
};
// month 1-12
class
m_formatter
final
:
public
flag_formatter
{
public
:
explicit
m_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_mon
+
1
,
dest
);
}
};
// day of month 1-31
class
d_formatter
final
:
public
flag_formatter
{
public
:
explicit
d_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_mday
,
dest
);
}
};
// hours in 24 format 0-23
class
H_formatter
final
:
public
flag_formatter
{
public
:
explicit
H_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_hour
,
dest
);
}
};
// hours in 12 format 1-12
class
I_formatter
final
:
public
flag_formatter
{
public
:
explicit
I_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
to12h
(
tm_time
),
dest
);
}
};
// minutes 0-59
class
M_formatter
final
:
public
flag_formatter
{
public
:
explicit
M_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_min
,
dest
);
}
};
// seconds 0-59
class
S_formatter
final
:
public
flag_formatter
{
public
:
explicit
S_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_sec
,
dest
);
}
};
// milliseconds
class
e_formatter
final
:
public
flag_formatter
{
public
:
explicit
e_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
auto
millis
=
fmt_helper
::
time_fraction
<
std
::
chrono
::
milliseconds
>
(
msg
.
time
);
if
(
padinfo_
.
enabled
())
{
const
size_t
field_size
=
3
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad3
(
static_cast
<
uint32_t
>
(
millis
.
count
()),
dest
);
}
else
{
fmt_helper
::
pad3
(
static_cast
<
uint32_t
>
(
millis
.
count
()),
dest
);
}
}
};
// microseconds
class
f_formatter
final
:
public
flag_formatter
{
public
:
explicit
f_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
auto
micros
=
fmt_helper
::
time_fraction
<
std
::
chrono
::
microseconds
>
(
msg
.
time
);
if
(
padinfo_
.
enabled
())
{
const
size_t
field_size
=
6
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad6
(
static_cast
<
size_t
>
(
micros
.
count
()),
dest
);
}
else
{
fmt_helper
::
pad6
(
static_cast
<
size_t
>
(
micros
.
count
()),
dest
);
}
}
};
// nanoseconds
class
F_formatter
final
:
public
flag_formatter
{
public
:
explicit
F_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
auto
ns
=
fmt_helper
::
time_fraction
<
std
::
chrono
::
nanoseconds
>
(
msg
.
time
);
if
(
padinfo_
.
enabled
())
{
const
size_t
field_size
=
9
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad9
(
static_cast
<
size_t
>
(
ns
.
count
()),
dest
);
}
else
{
fmt_helper
::
pad9
(
static_cast
<
size_t
>
(
ns
.
count
()),
dest
);
}
}
};
// seconds since epoch
class
E_formatter
final
:
public
flag_formatter
class
pattern_formatter
final
:
public
formatter
{
public
:
explicit
E_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
10
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
auto
duration
=
msg
.
time
.
time_since_epoch
();
auto
seconds
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
seconds
>
(
duration
).
count
();
fmt_helper
::
append_int
(
seconds
,
dest
);
}
};
explicit
pattern_formatter
(
std
::
string
pattern
,
pattern_time_type
time_type
=
pattern_time_type
::
local
,
std
::
string
eol
=
spdlog
::
details
::
os
::
default_eol
);
// AM/PM
class
p_formatter
final
:
public
flag_formatter
{
public
:
explicit
p_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
// use default pattern is not given
explicit
pattern_formatter
(
pattern_time_type
time_type
=
pattern_time_type
::
local
,
std
::
string
eol
=
spdlog
::
details
::
os
::
default_eol
);
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
ampm
(
tm_time
),
dest
);
}
};
pattern_formatter
(
const
pattern_formatter
&
other
)
=
delete
;
pattern_formatter
&
operator
=
(
const
pattern_formatter
&
other
)
=
delete
;
// 12 hour clock 02:55:02 pm
class
r_formatter
final
:
public
flag_formatter
{
public
:
explicit
r_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
std
::
unique_ptr
<
formatter
>
clone
()
const
override
;
void
format
(
const
details
::
log_msg
&
msg
,
fmt
::
memory_buffer
&
dest
)
override
;
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
11
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
private
:
std
::
string
pattern_
;
std
::
string
eol_
;
pattern_time_type
pattern_time_type_
;
std
::
tm
cached_tm_
;
std
::
chrono
::
seconds
last_log_secs_
;
std
::
vector
<
std
::
unique_ptr
<
details
::
flag_formatter
>>
formatters_
;
std
::
tm
get_time_
(
const
details
::
log_msg
&
msg
);
fmt_helper
::
pad2
(
to12h
(
tm_time
),
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_min
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_sec
,
dest
);
dest
.
push_back
(
' '
);
fmt_helper
::
append_string_view
(
ampm
(
tm_time
),
dest
);
}
};
void
handle_flag_
(
char
flag
,
details
::
padding_info
padding
);
// 24-hour HH:MM time, equivalent to %H:%M
class
R_formatter
final
:
public
flag_formatter
{
public
:
explicit
R_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
// Extract given pad spec (e.g. %8X)
// Advance the given it pass the end of the padding spec found (if any)
// Return padding.
details
::
padding_info
handle_padspec_
(
std
::
string
::
const_iterator
&
it
,
std
::
string
::
const_iterator
end
);
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
5
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_hour
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_min
,
dest
);
}
};
// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
class
T_formatter
final
:
public
flag_formatter
{
public
:
explicit
T_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
8
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_hour
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_min
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_sec
,
dest
);
}
};
// ISO 8601 offset from UTC in timezone (+-HH:MM)
class
z_formatter
final
:
public
flag_formatter
{
public
:
explicit
z_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
const
std
::
chrono
::
seconds
cache_refresh
=
std
::
chrono
::
seconds
(
5
);
z_formatter
()
=
default
;
z_formatter
(
const
z_formatter
&
)
=
delete
;
z_formatter
&
operator
=
(
const
z_formatter
&
)
=
delete
;
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
6
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
#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)
(
void
)(
msg
);
int
total_minutes
=
os
::
utc_minutes_offset
(
tm_time
);
#endif
bool
is_negative
=
total_minutes
<
0
;
if
(
is_negative
)
{
total_minutes
=
-
total_minutes
;
dest
.
push_back
(
'-'
);
}
else
{
dest
.
push_back
(
'+'
);
}
fmt_helper
::
pad2
(
total_minutes
/
60
,
dest
);
// hours
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
total_minutes
%
60
,
dest
);
// minutes
}
private
:
log_clock
::
time_point
last_update_
{
std
::
chrono
::
seconds
(
0
)};
#ifdef _WIN32
int
offset_minutes_
{
0
};
int
get_cached_offset
(
const
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
{
if
(
msg
.
time
-
last_update_
>=
cache_refresh
)
{
offset_minutes_
=
os
::
utc_minutes_offset
(
tm_time
);
last_update_
=
msg
.
time
;
}
return
offset_minutes_
;
}
#endif
};
// Thread id
class
t_formatter
final
:
public
flag_formatter
{
public
:
explicit
t_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
padinfo_
.
enabled
())
{
const
auto
field_size
=
fmt_helper
::
count_digits
(
msg
.
thread_id
);
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
append_int
(
msg
.
thread_id
,
dest
);
}
else
{
fmt_helper
::
append_int
(
msg
.
thread_id
,
dest
);
}
}
};
// Current pid
class
pid_formatter
final
:
public
flag_formatter
{
public
:
explicit
pid_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
const
auto
pid
=
static_cast
<
uint32_t
>
(
details
::
os
::
pid
());
if
(
padinfo_
.
enabled
())
{
auto
field_size
=
fmt_helper
::
count_digits
(
pid
);
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
append_int
(
pid
,
dest
);
}
else
{
fmt_helper
::
append_int
(
pid
,
dest
);
}
}
};
// message counter formatter
class
i_formatter
final
:
public
flag_formatter
{
public
:
explicit
i_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
6
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad6
(
msg
.
msg_id
,
dest
);
}
};
class
v_formatter
final
:
public
flag_formatter
{
public
:
explicit
v_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
padinfo_
.
enabled
())
{
scoped_pad
p
(
msg
.
payload
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
msg
.
payload
,
dest
);
}
else
{
fmt_helper
::
append_string_view
(
msg
.
payload
,
dest
);
}
}
};
class
ch_formatter
final
:
public
flag_formatter
{
public
:
explicit
ch_formatter
(
char
ch
)
:
ch_
(
ch
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
1
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
dest
.
push_back
(
ch_
);
}
private
:
char
ch_
;
};
// aggregate user chars to display as is
class
aggregate_formatter
final
:
public
flag_formatter
{
public
:
aggregate_formatter
()
=
default
;
void
add_ch
(
char
ch
)
{
str_
+=
ch
;
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
fmt_helper
::
append_string_view
(
str_
,
dest
);
}
private
:
std
::
string
str_
;
};
// mark the color range. expect it to be in the form of "%^colored text%$"
class
color_start_formatter
final
:
public
flag_formatter
{
public
:
explicit
color_start_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
msg
.
color_range_start
=
dest
.
size
();
}
};
class
color_stop_formatter
final
:
public
flag_formatter
{
public
:
explicit
color_stop_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
msg
.
color_range_end
=
dest
.
size
();
}
};
// print source location
class
source_location_formatter
final
:
public
flag_formatter
{
public
:
explicit
source_location_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
msg
.
source
.
empty
())
{
return
;
}
if
(
padinfo_
.
enabled
())
{
const
auto
text_size
=
std
::
char_traits
<
char
>::
length
(
msg
.
source
.
filename
)
+
fmt_helper
::
count_digits
(
msg
.
source
.
line
)
+
1
;
scoped_pad
p
(
text_size
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
msg
.
source
.
filename
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
append_int
(
msg
.
source
.
line
,
dest
);
}
else
{
fmt_helper
::
append_string_view
(
msg
.
source
.
filename
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
append_int
(
msg
.
source
.
line
,
dest
);
}
}
};
// print source filename
class
source_filename_formatter
final
:
public
flag_formatter
{
public
:
explicit
source_filename_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
msg
.
source
.
empty
())
{
return
;
}
scoped_pad
p
(
msg
.
source
.
filename
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
msg
.
source
.
filename
,
dest
);
}
};
class
source_linenum_formatter
final
:
public
flag_formatter
{
public
:
explicit
source_linenum_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
msg
.
source
.
empty
())
{
return
;
}
if
(
padinfo_
.
enabled
())
{
auto
field_size
=
fmt_helper
::
count_digits
(
msg
.
source
.
line
);
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
append_int
(
msg
.
source
.
line
,
dest
);
}
else
{
fmt_helper
::
append_int
(
msg
.
source
.
line
,
dest
);
}
}
};
// print source funcname
class
source_funcname_formatter
final
:
public
flag_formatter
{
public
:
explicit
source_funcname_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
msg
.
source
.
empty
())
{
return
;
}
scoped_pad
p
(
msg
.
source
.
funcname
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
msg
.
source
.
funcname
,
dest
);
}
};
// Full info formatter
// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
class
full_formatter
final
:
public
flag_formatter
{
public
:
explicit
full_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
using
std
::
chrono
::
duration_cast
;
using
std
::
chrono
::
milliseconds
;
using
std
::
chrono
::
seconds
;
#ifndef SPDLOG_NO_DATETIME
// cache the date/time part for the next second.
auto
duration
=
msg
.
time
.
time_since_epoch
();
auto
secs
=
duration_cast
<
seconds
>
(
duration
);
if
(
cache_timestamp_
!=
secs
||
cached_datetime_
.
size
()
==
0
)
{
cached_datetime_
.
clear
();
cached_datetime_
.
push_back
(
'['
);
fmt_helper
::
append_int
(
tm_time
.
tm_year
+
1900
,
cached_datetime_
);
cached_datetime_
.
push_back
(
'-'
);
fmt_helper
::
pad2
(
tm_time
.
tm_mon
+
1
,
cached_datetime_
);
cached_datetime_
.
push_back
(
'-'
);
fmt_helper
::
pad2
(
tm_time
.
tm_mday
,
cached_datetime_
);
cached_datetime_
.
push_back
(
' '
);
fmt_helper
::
pad2
(
tm_time
.
tm_hour
,
cached_datetime_
);
cached_datetime_
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_min
,
cached_datetime_
);
cached_datetime_
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_sec
,
cached_datetime_
);
cached_datetime_
.
push_back
(
'.'
);
cache_timestamp_
=
secs
;
}
fmt_helper
::
append_buf
(
cached_datetime_
,
dest
);
auto
millis
=
fmt_helper
::
time_fraction
<
milliseconds
>
(
msg
.
time
);
fmt_helper
::
pad3
(
static_cast
<
uint32_t
>
(
millis
.
count
()),
dest
);
dest
.
push_back
(
']'
);
dest
.
push_back
(
' '
);
#else // no datetime needed
(
void
)
tm_time
;
#endif
#ifndef SPDLOG_NO_NAME
if
(
!
msg
.
logger_name
->
empty
())
{
dest
.
push_back
(
'['
);
// fmt_helper::append_str(*msg.logger_name, dest);
fmt_helper
::
append_string_view
(
*
msg
.
logger_name
,
dest
);
dest
.
push_back
(
']'
);
dest
.
push_back
(
' '
);
}
#endif
dest
.
push_back
(
'['
);
// wrap the level name with color
msg
.
color_range_start
=
dest
.
size
();
// fmt_helper::append_string_view(level::to_c_str(msg.level), dest);
fmt_helper
::
append_string_view
(
level
::
to_string_view
(
msg
.
level
),
dest
);
msg
.
color_range_end
=
dest
.
size
();
dest
.
push_back
(
']'
);
dest
.
push_back
(
' '
);
// add source location if present
if
(
!
msg
.
source
.
empty
())
{
dest
.
push_back
(
'['
);
fmt_helper
::
append_string_view
(
msg
.
source
.
filename
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
append_int
(
msg
.
source
.
line
,
dest
);
dest
.
push_back
(
']'
);
dest
.
push_back
(
' '
);
}
// fmt_helper::append_string_view(msg.msg(), dest);
fmt_helper
::
append_string_view
(
msg
.
payload
,
dest
);
}
private
:
std
::
chrono
::
seconds
cache_timestamp_
{
0
};
fmt
::
basic_memory_buffer
<
char
,
128
>
cached_datetime_
;
};
}
// namespace details
class
pattern_formatter
final
:
public
formatter
{
public
:
explicit
pattern_formatter
(
std
::
string
pattern
,
pattern_time_type
time_type
=
pattern_time_type
::
local
,
std
::
string
eol
=
spdlog
::
details
::
os
::
default_eol
)
:
pattern_
(
std
::
move
(
pattern
))
,
eol_
(
std
::
move
(
eol
))
,
pattern_time_type_
(
time_type
)
,
last_log_secs_
(
0
)
{
std
::
memset
(
&
cached_tm_
,
0
,
sizeof
(
cached_tm_
));
compile_pattern_
(
pattern_
);
}
// use by default full formatter for if pattern is not given
explicit
pattern_formatter
(
pattern_time_type
time_type
=
pattern_time_type
::
local
,
std
::
string
eol
=
spdlog
::
details
::
os
::
default_eol
)
:
pattern_
(
"%+"
)
,
eol_
(
std
::
move
(
eol
))
,
pattern_time_type_
(
time_type
)
,
last_log_secs_
(
0
)
{
std
::
memset
(
&
cached_tm_
,
0
,
sizeof
(
cached_tm_
));
formatters_
.
push_back
(
details
::
make_unique
<
details
::
full_formatter
>
(
details
::
padding_info
{}));
}
pattern_formatter
(
const
pattern_formatter
&
other
)
=
delete
;
pattern_formatter
&
operator
=
(
const
pattern_formatter
&
other
)
=
delete
;
std
::
unique_ptr
<
formatter
>
clone
()
const
override
{
return
details
::
make_unique
<
pattern_formatter
>
(
pattern_
,
pattern_time_type_
,
eol_
);
}
void
format
(
const
details
::
log_msg
&
msg
,
fmt
::
memory_buffer
&
dest
)
override
{
#ifndef SPDLOG_NO_DATETIME
auto
secs
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
seconds
>
(
msg
.
time
.
time_since_epoch
());
if
(
secs
!=
last_log_secs_
)
{
cached_tm_
=
get_time_
(
msg
);
last_log_secs_
=
secs
;
}
#endif
for
(
auto
&
f
:
formatters_
)
{
f
->
format
(
msg
,
cached_tm_
,
dest
);
}
// write eol
details
::
fmt_helper
::
append_string_view
(
eol_
,
dest
);
}
private
:
std
::
string
pattern_
;
std
::
string
eol_
;
pattern_time_type
pattern_time_type_
;
std
::
tm
cached_tm_
;
std
::
chrono
::
seconds
last_log_secs_
;
std
::
vector
<
std
::
unique_ptr
<
details
::
flag_formatter
>>
formatters_
;
std
::
tm
get_time_
(
const
details
::
log_msg
&
msg
)
{
if
(
pattern_time_type_
==
pattern_time_type
::
local
)
{
return
details
::
os
::
localtime
(
log_clock
::
to_time_t
(
msg
.
time
));
}
return
details
::
os
::
gmtime
(
log_clock
::
to_time_t
(
msg
.
time
));
}
void
handle_flag_
(
char
flag
,
details
::
padding_info
padding
)
{
switch
(
flag
)
{
case
(
'+'
):
// default formatter
formatters_
.
push_back
(
details
::
make_unique
<
details
::
full_formatter
>
(
padding
));
break
;
case
'n'
:
// logger name
formatters_
.
push_back
(
details
::
make_unique
<
details
::
name_formatter
>
(
padding
));
break
;
case
'l'
:
// level
formatters_
.
push_back
(
details
::
make_unique
<
details
::
level_formatter
>
(
padding
));
break
;
case
'L'
:
// short level
formatters_
.
push_back
(
details
::
make_unique
<
details
::
short_level_formatter
>
(
padding
));
break
;
case
(
't'
):
// thread id
formatters_
.
push_back
(
details
::
make_unique
<
details
::
t_formatter
>
(
padding
));
break
;
case
(
'v'
):
// the message text
formatters_
.
push_back
(
details
::
make_unique
<
details
::
v_formatter
>
(
padding
));
break
;
case
(
'a'
):
// weekday
formatters_
.
push_back
(
details
::
make_unique
<
details
::
a_formatter
>
(
padding
));
break
;
case
(
'A'
):
// short weekday
formatters_
.
push_back
(
details
::
make_unique
<
details
::
A_formatter
>
(
padding
));
break
;
case
(
'b'
):
case
(
'h'
):
// month
formatters_
.
push_back
(
details
::
make_unique
<
details
::
b_formatter
>
(
padding
));
break
;
case
(
'B'
):
// short month
formatters_
.
push_back
(
details
::
make_unique
<
details
::
B_formatter
>
(
padding
));
break
;
case
(
'c'
):
// datetime
formatters_
.
push_back
(
details
::
make_unique
<
details
::
c_formatter
>
(
padding
));
break
;
case
(
'C'
):
// year 2 digits
formatters_
.
push_back
(
details
::
make_unique
<
details
::
C_formatter
>
(
padding
));
break
;
case
(
'Y'
):
// year 4 digits
formatters_
.
push_back
(
details
::
make_unique
<
details
::
Y_formatter
>
(
padding
));
break
;
case
(
'D'
):
case
(
'x'
):
// datetime MM/DD/YY
formatters_
.
push_back
(
details
::
make_unique
<
details
::
D_formatter
>
(
padding
));
break
;
case
(
'm'
):
// month 1-12
formatters_
.
push_back
(
details
::
make_unique
<
details
::
m_formatter
>
(
padding
));
break
;
case
(
'd'
):
// day of month 1-31
formatters_
.
push_back
(
details
::
make_unique
<
details
::
d_formatter
>
(
padding
));
break
;
case
(
'H'
):
// hours 24
formatters_
.
push_back
(
details
::
make_unique
<
details
::
H_formatter
>
(
padding
));
break
;
case
(
'I'
):
// hours 12
formatters_
.
push_back
(
details
::
make_unique
<
details
::
I_formatter
>
(
padding
));
break
;
case
(
'M'
):
// minutes
formatters_
.
push_back
(
details
::
make_unique
<
details
::
M_formatter
>
(
padding
));
break
;
case
(
'S'
):
// seconds
formatters_
.
push_back
(
details
::
make_unique
<
details
::
S_formatter
>
(
padding
));
break
;
case
(
'e'
):
// milliseconds
formatters_
.
push_back
(
details
::
make_unique
<
details
::
e_formatter
>
(
padding
));
break
;
case
(
'f'
):
// microseconds
formatters_
.
push_back
(
details
::
make_unique
<
details
::
f_formatter
>
(
padding
));
break
;
case
(
'F'
):
// nanoseconds
formatters_
.
push_back
(
details
::
make_unique
<
details
::
F_formatter
>
(
padding
));
break
;
case
(
'E'
):
// seconds since epoch
formatters_
.
push_back
(
details
::
make_unique
<
details
::
E_formatter
>
(
padding
));
break
;
case
(
'p'
):
// am/pm
formatters_
.
push_back
(
details
::
make_unique
<
details
::
p_formatter
>
(
padding
));
break
;
case
(
'r'
):
// 12 hour clock 02:55:02 pm
formatters_
.
push_back
(
details
::
make_unique
<
details
::
r_formatter
>
(
padding
));
break
;
case
(
'R'
):
// 24-hour HH:MM time
formatters_
.
push_back
(
details
::
make_unique
<
details
::
R_formatter
>
(
padding
));
break
;
case
(
'T'
):
case
(
'X'
):
// ISO 8601 time format (HH:MM:SS)
formatters_
.
push_back
(
details
::
make_unique
<
details
::
T_formatter
>
(
padding
));
break
;
case
(
'z'
):
// timezone
formatters_
.
push_back
(
details
::
make_unique
<
details
::
z_formatter
>
(
padding
));
break
;
case
(
'P'
):
// pid
formatters_
.
push_back
(
details
::
make_unique
<
details
::
pid_formatter
>
(
padding
));
break
;
#ifdef SPDLOG_ENABLE_MESSAGE_COUNTER
case
(
'i'
):
formatters_
.
push_back
(
details
::
make_unique
<
details
::
i_formatter
>
(
padding
));
break
;
#endif
case
(
'^'
):
// color range start
formatters_
.
push_back
(
details
::
make_unique
<
details
::
color_start_formatter
>
(
padding
));
break
;
case
(
'$'
):
// color range end
formatters_
.
push_back
(
details
::
make_unique
<
details
::
color_stop_formatter
>
(
padding
));
break
;
case
(
'@'
):
// source location (filename:filenumber)
formatters_
.
push_back
(
details
::
make_unique
<
details
::
source_location_formatter
>
(
padding
));
break
;
case
(
's'
):
// source filename
formatters_
.
push_back
(
details
::
make_unique
<
details
::
source_filename_formatter
>
(
padding
));
break
;
case
(
'#'
):
// source line number
formatters_
.
push_back
(
details
::
make_unique
<
details
::
source_linenum_formatter
>
(
padding
));
break
;
case
(
'!'
):
// source funcname
formatters_
.
push_back
(
details
::
make_unique
<
details
::
source_funcname_formatter
>
(
padding
));
break
;
case
(
'%'
):
// % char
formatters_
.
push_back
(
details
::
make_unique
<
details
::
ch_formatter
>
(
'%'
));
break
;
default
:
// Unknown flag appears as is
auto
unknown_flag
=
details
::
make_unique
<
details
::
aggregate_formatter
>
();
unknown_flag
->
add_ch
(
'%'
);
unknown_flag
->
add_ch
(
flag
);
formatters_
.
push_back
((
std
::
move
(
unknown_flag
)));
break
;
}
}
// Extract given pad spec (e.g. %8X)
// Advance the given it pass the end of the padding spec found (if any)
// Return padding.
details
::
padding_info
handle_padspec_
(
std
::
string
::
const_iterator
&
it
,
std
::
string
::
const_iterator
end
)
{
using
details
::
padding_info
;
using
details
::
scoped_pad
;
const
size_t
max_width
=
128
;
if
(
it
==
end
)
{
return
padding_info
{};
}
padding_info
::
pad_side
side
;
switch
(
*
it
)
{
case
'-'
:
side
=
padding_info
::
right
;
++
it
;
break
;
case
'='
:
side
=
padding_info
::
center
;
++
it
;
break
;
default
:
side
=
details
::
padding_info
::
left
;
break
;
}
if
(
it
==
end
||
!
std
::
isdigit
(
static_cast
<
unsigned
char
>
(
*
it
)))
{
return
padding_info
{
0
,
side
};
}
auto
width
=
static_cast
<
size_t
>
(
*
it
-
'0'
);
for
(
++
it
;
it
!=
end
&&
std
::
isdigit
(
static_cast
<
unsigned
char
>
(
*
it
));
++
it
)
{
auto
digit
=
static_cast
<
size_t
>
(
*
it
-
'0'
);
width
=
width
*
10
+
digit
;
}
return
details
::
padding_info
{
std
::
min
<
size_t
>
(
width
,
max_width
),
side
};
}
void
compile_pattern_
(
const
std
::
string
&
pattern
)
{
auto
end
=
pattern
.
end
();
std
::
unique_ptr
<
details
::
aggregate_formatter
>
user_chars
;
formatters_
.
clear
();
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
));
}
auto
padding
=
handle_padspec_
(
++
it
,
end
);
if
(
it
!=
end
)
{
handle_flag_
(
*
it
,
padding
);
}
else
{
break
;
}
}
else
// chars not following the % sign should be displayed as is
{
if
(
!
user_chars
)
{
user_chars
=
details
::
make_unique
<
details
::
aggregate_formatter
>
();
}
user_chars
->
add_ch
(
*
it
);
}
}
if
(
user_chars
)
// append raw chars found so far
{
formatters_
.
push_back
(
std
::
move
(
user_chars
));
}
}
void
compile_pattern_
(
const
std
::
string
&
pattern
);
};
}
// namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
#include "../src/
os
.cpp"
#include "../src/
pattern_formatter
.cpp"
#endif
include/spdlog/details/registry.h
View file @
17f9cdd4
...
...
@@ -154,7 +154,7 @@ public:
periodic_flusher_
=
details
::
make_unique
<
periodic_worker
>
(
clbk
,
interval
);
}
void
set_error_handler
(
log_err_handler
handler
)
void
set_error_handler
(
void
(
*
handler
)(
const
std
::
string
&
msg
)
)
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
logger_map_mutex_
);
for
(
auto
&
l
:
loggers_
)
...
...
@@ -275,7 +275,7 @@ private:
std
::
unique_ptr
<
formatter
>
formatter_
;
level
::
level_enum
level_
=
spdlog
::
logger
::
default_level
();
level
::
level_enum
flush_level_
=
level
::
off
;
log_err_handler
err_handler_
;
void
(
*
err_handler_
)(
const
std
::
string
&
msg
)
;
std
::
shared_ptr
<
thread_pool
>
tp_
;
std
::
unique_ptr
<
periodic_worker
>
periodic_flusher_
;
std
::
shared_ptr
<
logger
>
default_logger_
;
...
...
include/spdlog/logger.h
View file @
17f9cdd4
...
...
@@ -17,22 +17,17 @@
// The use of private formatter per sink provides the opportunity to cache some
// formatted data, and support for different format per sink.
#include "spdlog/common.h"
#include "spdlog/details/log_msg.h"
//#include "spdlog/formatter.h"
//#include "spdlog/sinks/sink.h"
#include <memory>
#include <string>
#include <vector>
namespace
spdlog
namespace
spdlog
{
class
logger
{
class
logger
{
public
:
public
:
template
<
typename
It
>
logger
(
std
::
string
name
,
It
begin
,
It
end
)
:
name_
(
std
::
move
(
name
))
...
...
@@ -332,9 +327,7 @@ namespace spdlog
std
::
vector
<
sink_ptr
>
&
sinks
();
// error handler
void
set_error_handler
(
log_err_handler
err_handler
);
log_err_handler
error_handler
()
const
;
void
set_error_handler
(
void
(
*
handler
)(
const
std
::
string
&
msg
));
// create new logger with same sinks and configuration.
virtual
std
::
shared_ptr
<
logger
>
clone
(
std
::
string
logger_name
);
...
...
@@ -347,7 +340,7 @@ namespace spdlog
// default error handler.
// print the error to stderr with the max rate of 1 message/minute.
void
default_
err_handler_
(
const
std
::
string
&
msg
);
void
err_handler_
(
const
std
::
string
&
msg
);
// increment the message count (only if defined(SPDLOG_ENABLE_MESSAGE_COUNTER))
void
incr_msg_counter_
(
details
::
log_msg
&
msg
);
...
...
@@ -356,10 +349,8 @@ namespace spdlog
std
::
vector
<
sink_ptr
>
sinks_
;
spdlog
::
level_t
level_
{
spdlog
::
logger
::
default_level
()};
spdlog
::
level_t
flush_level_
{
level
::
off
};
log_err_handler
err_handler_
{[
this
](
const
std
::
string
&
msg
)
{
this
->
default_err_handler_
(
msg
);
}};
std
::
atomic
<
time_t
>
last_err_time_
{
0
};
std
::
atomic
<
size_t
>
msg_counter_
{
1
};
};
void
(
*
custom_err_handler_
)(
const
std
::
string
&
msg
)
{
nullptr
};
};
}
// namespace spdlog
#ifdef SPDLOG_HEADER_ONLY
...
...
include/spdlog/spdlog.h
View file @
17f9cdd4
...
...
@@ -103,9 +103,9 @@ inline void flush_every(std::chrono::seconds interval)
}
// Set global error handler
inline
void
set_error_handler
(
log_err_handler
handler
)
inline
void
set_error_handler
(
void
(
*
handler
)(
const
std
::
string
&
msg
)
)
{
details
::
registry
::
instance
().
set_error_handler
(
std
::
move
(
handler
)
);
details
::
registry
::
instance
().
set_error_handler
(
handler
);
}
// Register the given logger with the given name
...
...
include/spdlog/tweakme.h
View file @
17f9cdd4
...
...
@@ -107,13 +107,6 @@
// #define SPDLOG_PREVENT_CHILD_FD
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to enable message counting feature.
// Use the %i in the logger pattern to display log message sequence id.
//
// #define SPDLOG_ENABLE_MESSAGE_COUNTER
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to customize level names (e.g. "MT TRACE")
//
...
...
src/logger.cpp
View file @
17f9cdd4
...
...
@@ -113,14 +113,9 @@ SPDLOG_INLINE std::vector<spdlog::sink_ptr> &spdlog::logger::sinks()
}
// error handler
SPDLOG_INLINE
void
spdlog
::
logger
::
set_error_handler
(
spdlog
::
log_err_handler
err_handler
)
SPDLOG_INLINE
void
spdlog
::
logger
::
set_error_handler
(
void
(
*
handler
)(
const
std
::
string
&
msg
)
)
{
err_handler_
=
std
::
move
(
err_handler
);
}
SPDLOG_INLINE
spdlog
::
log_err_handler
spdlog
::
logger
::
error_handler
()
const
{
return
err_handler_
;
custom_err_handler_
=
handler
;
}
// create new logger with same sinks and configuration.
...
...
@@ -129,16 +124,13 @@ SPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::logger::clone(std::string
auto
cloned
=
std
::
make_shared
<
spdlog
::
logger
>
(
std
::
move
(
logger_name
),
sinks_
.
begin
(),
sinks_
.
end
());
cloned
->
set_level
(
this
->
level
());
cloned
->
flush_on
(
this
->
flush_level
());
cloned
->
set_error_handler
(
this
->
error_handler
()
);
cloned
->
set_error_handler
(
this
->
custom_err_handler_
);
return
cloned
;
}
// protected methods
SPDLOG_INLINE
void
spdlog
::
logger
::
sink_it_
(
spdlog
::
details
::
log_msg
&
msg
)
{
#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)
incr_msg_counter_
(
msg
);
#endif
for
(
auto
&
sink
:
sinks_
)
{
if
(
sink
->
should_log
(
msg
.
level
))
...
...
@@ -167,21 +159,17 @@ SPDLOG_INLINE bool spdlog::logger::should_flush_(const spdlog::details::log_msg
return
(
msg
.
level
>=
flush_level
)
&&
(
msg
.
level
!=
level
::
off
);
}
SPDLOG_INLINE
void
spdlog
::
logger
::
default_
err_handler_
(
const
std
::
string
&
msg
)
void
spdlog
::
logger
::
err_handler_
(
const
std
::
string
&
msg
)
{
auto
now
=
time
(
nullptr
);
if
(
now
-
last_err_time_
<
60
)
if
(
custom_err_handler_
)
{
return
;
custom_err_handler_
(
msg
)
;
}
last_err_time_
=
now
;
auto
tm_time
=
details
::
os
::
localtime
(
now
);
char
date_buf
[
100
];
else
{
auto
tm_time
=
spdlog
::
details
::
os
::
localtime
();
char
date_buf
[
64
];
std
::
strftime
(
date_buf
,
sizeof
(
date_buf
),
"%Y-%m-%d %H:%M:%S"
,
&
tm_time
);
fmt
::
print
(
stderr
,
"[*** LOG ERROR ***] [{}] [{}] {}
\n
"
,
date_buf
,
name
(),
msg
);
}
SPDLOG_INLINE
void
spdlog
::
logger
::
incr_msg_counter_
(
spdlog
::
details
::
log_msg
&
msg
)
{
msg
.
msg_id
=
msg_counter_
.
fetch_add
(
1
,
std
::
memory_order_relaxed
);
}
}
\ No newline at end of file
src/os.cpp
View file @
17f9cdd4
...
...
@@ -344,14 +344,12 @@ SPDLOG_INLINE void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT
// 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
SPDLOG_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
SPDLOG_INLINE
std
::
string
filename_to_str
(
const
filename_t
&
filename
)
{
return
filename
;
...
...
src/pattern_formatter.cpp
0 → 100644
View file @
17f9cdd4
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//
#ifndef SPDLOG_HEADER_ONLY
#include "spdlog/details/pattern_formatter.h"
#endif // !SPDLOG_HEADER_ONLY
#include "spdlog/details/fmt_helper.h"
#include "spdlog/details/log_msg.h"
#include "spdlog/details/os.h"
#include "spdlog/fmt/fmt.h"
#include "spdlog/formatter.h"
#include <array>
#include <chrono>
#include <ctime>
#include <cctype>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <utility>
#include <vector>
namespace
spdlog
{
namespace
details
{
///////////////////////////////////////////////////////////////////////
// name & level pattern appender
///////////////////////////////////////////////////////////////////////
class
scoped_pad
{
public
:
scoped_pad
(
size_t
wrapped_size
,
padding_info
&
padinfo
,
fmt
::
memory_buffer
&
dest
)
:
padinfo_
(
padinfo
)
,
dest_
(
dest
)
{
if
(
padinfo_
.
width_
<=
wrapped_size
)
{
total_pad_
=
0
;
return
;
}
total_pad_
=
padinfo
.
width_
-
wrapped_size
;
if
(
padinfo_
.
side_
==
padding_info
::
left
)
{
pad_it
(
total_pad_
);
total_pad_
=
0
;
}
else
if
(
padinfo_
.
side_
==
padding_info
::
center
)
{
auto
half_pad
=
total_pad_
/
2
;
auto
reminder
=
total_pad_
&
1
;
pad_it
(
half_pad
);
total_pad_
=
half_pad
+
reminder
;
// for the right side
}
}
scoped_pad
(
spdlog
::
string_view_t
txt
,
padding_info
&
padinfo
,
fmt
::
memory_buffer
&
dest
)
:
scoped_pad
(
txt
.
size
(),
padinfo
,
dest
)
{
}
~
scoped_pad
()
{
if
(
total_pad_
)
{
pad_it
(
total_pad_
);
}
}
private
:
void
pad_it
(
size_t
count
)
{
// count = std::min(count, spaces_.size());
assert
(
count
<=
spaces_
.
size
());
fmt_helper
::
append_string_view
(
string_view_t
(
spaces_
.
data
(),
count
),
dest_
);
}
const
padding_info
&
padinfo_
;
fmt
::
memory_buffer
&
dest_
;
size_t
total_pad_
;
string_view_t
spaces_
{
" "
" "
,
128
};
};
class
name_formatter
:
public
flag_formatter
{
public
:
explicit
name_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
padinfo_
.
enabled
())
{
scoped_pad
p
(
*
msg
.
logger_name
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
*
msg
.
logger_name
,
dest
);
}
else
{
fmt_helper
::
append_string_view
(
*
msg
.
logger_name
,
dest
);
}
}
};
// log level appender
class
level_formatter
:
public
flag_formatter
{
public
:
explicit
level_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
string_view_t
&
level_name
=
level
::
to_string_view
(
msg
.
level
);
if
(
padinfo_
.
enabled
())
{
scoped_pad
p
(
level_name
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
level_name
,
dest
);
}
else
{
fmt_helper
::
append_string_view
(
level_name
,
dest
);
}
}
};
// short log level appender
class
short_level_formatter
:
public
flag_formatter
{
public
:
explicit
short_level_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
string_view_t
level_name
{
level
::
to_short_c_str
(
msg
.
level
)};
scoped_pad
p
(
level_name
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
level_name
,
dest
);
}
};
///////////////////////////////////////////////////////////////////////
// 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
char
*
days
[]{
"Sun"
,
"Mon"
,
"Tue"
,
"Wed"
,
"Thu"
,
"Fri"
,
"Sat"
};
class
a_formatter
:
public
flag_formatter
{
public
:
explicit
a_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
string_view_t
field_value
{
days
[
tm_time
.
tm_wday
]};
scoped_pad
p
(
field_value
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
field_value
,
dest
);
}
};
// Full weekday name
static
const
char
*
full_days
[]{
"Sunday"
,
"Monday"
,
"Tuesday"
,
"Wednesday"
,
"Thursday"
,
"Friday"
,
"Saturday"
};
class
A_formatter
:
public
flag_formatter
{
public
:
explicit
A_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
string_view_t
field_value
{
full_days
[
tm_time
.
tm_wday
]};
scoped_pad
p
(
field_value
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
field_value
,
dest
);
}
};
// Abbreviated month
static
const
char
*
months
[]{
"Jan"
,
"Feb"
,
"Mar"
,
"Apr"
,
"May"
,
"Jun"
,
"Jul"
,
"Aug"
,
"Sept"
,
"Oct"
,
"Nov"
,
"Dec"
};
class
b_formatter
:
public
flag_formatter
{
public
:
explicit
b_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
string_view_t
field_value
{
months
[
tm_time
.
tm_mon
]};
scoped_pad
p
(
field_value
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
field_value
,
dest
);
}
};
// Full month name
static
const
char
*
full_months
[]{
"January"
,
"February"
,
"March"
,
"April"
,
"May"
,
"June"
,
"July"
,
"August"
,
"September"
,
"October"
,
"November"
,
"December"
};
class
B_formatter
:
public
flag_formatter
{
public
:
explicit
B_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
string_view_t
field_value
{
full_months
[
tm_time
.
tm_mon
]};
scoped_pad
p
(
field_value
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
field_value
,
dest
);
}
};
// Date and time representation (Thu Aug 23 15:35:46 2014)
class
c_formatter
final
:
public
flag_formatter
{
public
:
explicit
c_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
24
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
days
[
tm_time
.
tm_wday
],
dest
);
dest
.
push_back
(
' '
);
fmt_helper
::
append_string_view
(
months
[
tm_time
.
tm_mon
],
dest
);
dest
.
push_back
(
' '
);
fmt_helper
::
append_int
(
tm_time
.
tm_mday
,
dest
);
dest
.
push_back
(
' '
);
// time
fmt_helper
::
pad2
(
tm_time
.
tm_hour
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_min
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_sec
,
dest
);
dest
.
push_back
(
' '
);
fmt_helper
::
append_int
(
tm_time
.
tm_year
+
1900
,
dest
);
}
};
// year - 2 digit
class
C_formatter
final
:
public
flag_formatter
{
public
:
explicit
C_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_year
%
100
,
dest
);
}
};
// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01
class
D_formatter
final
:
public
flag_formatter
{
public
:
explicit
D_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
10
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_mon
+
1
,
dest
);
dest
.
push_back
(
'/'
);
fmt_helper
::
pad2
(
tm_time
.
tm_mday
,
dest
);
dest
.
push_back
(
'/'
);
fmt_helper
::
pad2
(
tm_time
.
tm_year
%
100
,
dest
);
}
};
// year - 4 digit
class
Y_formatter
final
:
public
flag_formatter
{
public
:
explicit
Y_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
4
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
append_int
(
tm_time
.
tm_year
+
1900
,
dest
);
}
};
// month 1-12
class
m_formatter
final
:
public
flag_formatter
{
public
:
explicit
m_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_mon
+
1
,
dest
);
}
};
// day of month 1-31
class
d_formatter
final
:
public
flag_formatter
{
public
:
explicit
d_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_mday
,
dest
);
}
};
// hours in 24 format 0-23
class
H_formatter
final
:
public
flag_formatter
{
public
:
explicit
H_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_hour
,
dest
);
}
};
// hours in 12 format 1-12
class
I_formatter
final
:
public
flag_formatter
{
public
:
explicit
I_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
to12h
(
tm_time
),
dest
);
}
};
// minutes 0-59
class
M_formatter
final
:
public
flag_formatter
{
public
:
explicit
M_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_min
,
dest
);
}
};
// seconds 0-59
class
S_formatter
final
:
public
flag_formatter
{
public
:
explicit
S_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_sec
,
dest
);
}
};
// milliseconds
class
e_formatter
final
:
public
flag_formatter
{
public
:
explicit
e_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
auto
millis
=
fmt_helper
::
time_fraction
<
std
::
chrono
::
milliseconds
>
(
msg
.
time
);
if
(
padinfo_
.
enabled
())
{
const
size_t
field_size
=
3
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad3
(
static_cast
<
uint32_t
>
(
millis
.
count
()),
dest
);
}
else
{
fmt_helper
::
pad3
(
static_cast
<
uint32_t
>
(
millis
.
count
()),
dest
);
}
}
};
// microseconds
class
f_formatter
final
:
public
flag_formatter
{
public
:
explicit
f_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
auto
micros
=
fmt_helper
::
time_fraction
<
std
::
chrono
::
microseconds
>
(
msg
.
time
);
if
(
padinfo_
.
enabled
())
{
const
size_t
field_size
=
6
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad6
(
static_cast
<
size_t
>
(
micros
.
count
()),
dest
);
}
else
{
fmt_helper
::
pad6
(
static_cast
<
size_t
>
(
micros
.
count
()),
dest
);
}
}
};
// nanoseconds
class
F_formatter
final
:
public
flag_formatter
{
public
:
explicit
F_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
auto
ns
=
fmt_helper
::
time_fraction
<
std
::
chrono
::
nanoseconds
>
(
msg
.
time
);
if
(
padinfo_
.
enabled
())
{
const
size_t
field_size
=
9
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad9
(
static_cast
<
size_t
>
(
ns
.
count
()),
dest
);
}
else
{
fmt_helper
::
pad9
(
static_cast
<
size_t
>
(
ns
.
count
()),
dest
);
}
}
};
// seconds since epoch
class
E_formatter
final
:
public
flag_formatter
{
public
:
explicit
E_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
10
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
auto
duration
=
msg
.
time
.
time_since_epoch
();
auto
seconds
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
seconds
>
(
duration
).
count
();
fmt_helper
::
append_int
(
seconds
,
dest
);
}
};
// AM/PM
class
p_formatter
final
:
public
flag_formatter
{
public
:
explicit
p_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
2
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
ampm
(
tm_time
),
dest
);
}
};
// 12 hour clock 02:55:02 pm
class
r_formatter
final
:
public
flag_formatter
{
public
:
explicit
r_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
11
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
to12h
(
tm_time
),
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_min
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_sec
,
dest
);
dest
.
push_back
(
' '
);
fmt_helper
::
append_string_view
(
ampm
(
tm_time
),
dest
);
}
};
// 24-hour HH:MM time, equivalent to %H:%M
class
R_formatter
final
:
public
flag_formatter
{
public
:
explicit
R_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
5
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_hour
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_min
,
dest
);
}
};
// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
class
T_formatter
final
:
public
flag_formatter
{
public
:
explicit
T_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
8
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
pad2
(
tm_time
.
tm_hour
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_min
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_sec
,
dest
);
}
};
// ISO 8601 offset from UTC in timezone (+-HH:MM)
class
z_formatter
final
:
public
flag_formatter
{
public
:
explicit
z_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
const
std
::
chrono
::
seconds
cache_refresh
=
std
::
chrono
::
seconds
(
5
);
z_formatter
()
=
default
;
z_formatter
(
const
z_formatter
&
)
=
delete
;
z_formatter
&
operator
=
(
const
z_formatter
&
)
=
delete
;
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
6
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
#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)
(
void
)(
msg
);
int
total_minutes
=
os
::
utc_minutes_offset
(
tm_time
);
#endif
bool
is_negative
=
total_minutes
<
0
;
if
(
is_negative
)
{
total_minutes
=
-
total_minutes
;
dest
.
push_back
(
'-'
);
}
else
{
dest
.
push_back
(
'+'
);
}
fmt_helper
::
pad2
(
total_minutes
/
60
,
dest
);
// hours
dest
.
push_back
(
':'
);
fmt_helper
::
pad2
(
total_minutes
%
60
,
dest
);
// minutes
}
private
:
log_clock
::
time_point
last_update_
{
std
::
chrono
::
seconds
(
0
)};
#ifdef _WIN32
int
offset_minutes_
{
0
};
int
get_cached_offset
(
const
log_msg
&
msg
,
const
std
::
tm
&
tm_time
)
{
if
(
msg
.
time
-
last_update_
>=
cache_refresh
)
{
offset_minutes_
=
os
::
utc_minutes_offset
(
tm_time
);
last_update_
=
msg
.
time
;
}
return
offset_minutes_
;
}
#endif
};
// Thread id
class
t_formatter
final
:
public
flag_formatter
{
public
:
explicit
t_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
padinfo_
.
enabled
())
{
const
auto
field_size
=
fmt_helper
::
count_digits
(
msg
.
thread_id
);
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
append_int
(
msg
.
thread_id
,
dest
);
}
else
{
fmt_helper
::
append_int
(
msg
.
thread_id
,
dest
);
}
}
};
// Current pid
class
pid_formatter
final
:
public
flag_formatter
{
public
:
explicit
pid_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
const
auto
pid
=
static_cast
<
uint32_t
>
(
details
::
os
::
pid
());
if
(
padinfo_
.
enabled
())
{
auto
field_size
=
fmt_helper
::
count_digits
(
pid
);
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
append_int
(
pid
,
dest
);
}
else
{
fmt_helper
::
append_int
(
pid
,
dest
);
}
}
};
class
v_formatter
final
:
public
flag_formatter
{
public
:
explicit
v_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
padinfo_
.
enabled
())
{
scoped_pad
p
(
msg
.
payload
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
msg
.
payload
,
dest
);
}
else
{
fmt_helper
::
append_string_view
(
msg
.
payload
,
dest
);
}
}
};
class
ch_formatter
final
:
public
flag_formatter
{
public
:
explicit
ch_formatter
(
char
ch
)
:
ch_
(
ch
)
{
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
const
size_t
field_size
=
1
;
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
dest
.
push_back
(
ch_
);
}
private
:
char
ch_
;
};
// aggregate user chars to display as is
class
aggregate_formatter
final
:
public
flag_formatter
{
public
:
aggregate_formatter
()
=
default
;
void
add_ch
(
char
ch
)
{
str_
+=
ch
;
}
void
format
(
const
details
::
log_msg
&
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
fmt_helper
::
append_string_view
(
str_
,
dest
);
}
private
:
std
::
string
str_
;
};
// mark the color range. expect it to be in the form of "%^colored text%$"
class
color_start_formatter
final
:
public
flag_formatter
{
public
:
explicit
color_start_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
msg
.
color_range_start
=
dest
.
size
();
}
};
class
color_stop_formatter
final
:
public
flag_formatter
{
public
:
explicit
color_stop_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
msg
.
color_range_end
=
dest
.
size
();
}
};
// print source location
class
source_location_formatter
final
:
public
flag_formatter
{
public
:
explicit
source_location_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
msg
.
source
.
empty
())
{
return
;
}
if
(
padinfo_
.
enabled
())
{
const
auto
text_size
=
std
::
char_traits
<
char
>::
length
(
msg
.
source
.
filename
)
+
fmt_helper
::
count_digits
(
msg
.
source
.
line
)
+
1
;
scoped_pad
p
(
text_size
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
msg
.
source
.
filename
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
append_int
(
msg
.
source
.
line
,
dest
);
}
else
{
fmt_helper
::
append_string_view
(
msg
.
source
.
filename
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
append_int
(
msg
.
source
.
line
,
dest
);
}
}
};
// print source filename
class
source_filename_formatter
final
:
public
flag_formatter
{
public
:
explicit
source_filename_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
msg
.
source
.
empty
())
{
return
;
}
scoped_pad
p
(
msg
.
source
.
filename
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
msg
.
source
.
filename
,
dest
);
}
};
class
source_linenum_formatter
final
:
public
flag_formatter
{
public
:
explicit
source_linenum_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
msg
.
source
.
empty
())
{
return
;
}
if
(
padinfo_
.
enabled
())
{
auto
field_size
=
fmt_helper
::
count_digits
(
msg
.
source
.
line
);
scoped_pad
p
(
field_size
,
padinfo_
,
dest
);
fmt_helper
::
append_int
(
msg
.
source
.
line
,
dest
);
}
else
{
fmt_helper
::
append_int
(
msg
.
source
.
line
,
dest
);
}
}
};
// print source funcname
class
source_funcname_formatter
final
:
public
flag_formatter
{
public
:
explicit
source_funcname_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
){};
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
,
fmt
::
memory_buffer
&
dest
)
override
{
if
(
msg
.
source
.
empty
())
{
return
;
}
scoped_pad
p
(
msg
.
source
.
funcname
,
padinfo_
,
dest
);
fmt_helper
::
append_string_view
(
msg
.
source
.
funcname
,
dest
);
}
};
// Full info formatter
// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
class
full_formatter
final
:
public
flag_formatter
{
public
:
explicit
full_formatter
(
padding_info
padinfo
)
:
flag_formatter
(
padinfo
)
{
}
void
format
(
const
details
::
log_msg
&
msg
,
const
std
::
tm
&
tm_time
,
fmt
::
memory_buffer
&
dest
)
override
{
using
std
::
chrono
::
duration_cast
;
using
std
::
chrono
::
milliseconds
;
using
std
::
chrono
::
seconds
;
#ifndef SPDLOG_NO_DATETIME
// cache the date/time part for the next second.
auto
duration
=
msg
.
time
.
time_since_epoch
();
auto
secs
=
duration_cast
<
seconds
>
(
duration
);
if
(
cache_timestamp_
!=
secs
||
cached_datetime_
.
size
()
==
0
)
{
cached_datetime_
.
clear
();
cached_datetime_
.
push_back
(
'['
);
fmt_helper
::
append_int
(
tm_time
.
tm_year
+
1900
,
cached_datetime_
);
cached_datetime_
.
push_back
(
'-'
);
fmt_helper
::
pad2
(
tm_time
.
tm_mon
+
1
,
cached_datetime_
);
cached_datetime_
.
push_back
(
'-'
);
fmt_helper
::
pad2
(
tm_time
.
tm_mday
,
cached_datetime_
);
cached_datetime_
.
push_back
(
' '
);
fmt_helper
::
pad2
(
tm_time
.
tm_hour
,
cached_datetime_
);
cached_datetime_
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_min
,
cached_datetime_
);
cached_datetime_
.
push_back
(
':'
);
fmt_helper
::
pad2
(
tm_time
.
tm_sec
,
cached_datetime_
);
cached_datetime_
.
push_back
(
'.'
);
cache_timestamp_
=
secs
;
}
fmt_helper
::
append_buf
(
cached_datetime_
,
dest
);
auto
millis
=
fmt_helper
::
time_fraction
<
milliseconds
>
(
msg
.
time
);
fmt_helper
::
pad3
(
static_cast
<
uint32_t
>
(
millis
.
count
()),
dest
);
dest
.
push_back
(
']'
);
dest
.
push_back
(
' '
);
#else // no datetime needed
(
void
)
tm_time
;
#endif
#ifndef SPDLOG_NO_NAME
if
(
!
msg
.
logger_name
->
empty
())
{
dest
.
push_back
(
'['
);
// fmt_helper::append_str(*msg.logger_name, dest);
fmt_helper
::
append_string_view
(
*
msg
.
logger_name
,
dest
);
dest
.
push_back
(
']'
);
dest
.
push_back
(
' '
);
}
#endif
dest
.
push_back
(
'['
);
// wrap the level name with color
msg
.
color_range_start
=
dest
.
size
();
// fmt_helper::append_string_view(level::to_c_str(msg.level), dest);
fmt_helper
::
append_string_view
(
level
::
to_string_view
(
msg
.
level
),
dest
);
msg
.
color_range_end
=
dest
.
size
();
dest
.
push_back
(
']'
);
dest
.
push_back
(
' '
);
// add source location if present
if
(
!
msg
.
source
.
empty
())
{
dest
.
push_back
(
'['
);
fmt_helper
::
append_string_view
(
msg
.
source
.
filename
,
dest
);
dest
.
push_back
(
':'
);
fmt_helper
::
append_int
(
msg
.
source
.
line
,
dest
);
dest
.
push_back
(
']'
);
dest
.
push_back
(
' '
);
}
// fmt_helper::append_string_view(msg.msg(), dest);
fmt_helper
::
append_string_view
(
msg
.
payload
,
dest
);
}
private
:
std
::
chrono
::
seconds
cache_timestamp_
{
0
};
fmt
::
basic_memory_buffer
<
char
,
128
>
cached_datetime_
;
};
}
// namespace details
pattern_formatter
::
pattern_formatter
(
std
::
string
pattern
,
pattern_time_type
time_type
,
std
::
string
eol
)
:
pattern_
(
std
::
move
(
pattern
))
,
eol_
(
std
::
move
(
eol
))
,
pattern_time_type_
(
time_type
)
,
last_log_secs_
(
0
)
{
std
::
memset
(
&
cached_tm_
,
0
,
sizeof
(
cached_tm_
));
compile_pattern_
(
pattern_
);
}
// use by default full formatter for if pattern is not given
pattern_formatter
::
pattern_formatter
(
pattern_time_type
time_type
,
std
::
string
eol
)
:
pattern_
(
"%+"
)
,
eol_
(
std
::
move
(
eol
))
,
pattern_time_type_
(
time_type
)
,
last_log_secs_
(
0
)
{
std
::
memset
(
&
cached_tm_
,
0
,
sizeof
(
cached_tm_
));
formatters_
.
push_back
(
details
::
make_unique
<
details
::
full_formatter
>
(
details
::
padding_info
{}));
}
std
::
unique_ptr
<
formatter
>
pattern_formatter
::
clone
()
const
{
return
details
::
make_unique
<
pattern_formatter
>
(
pattern_
,
pattern_time_type_
,
eol_
);
}
void
pattern_formatter
::
format
(
const
details
::
log_msg
&
msg
,
fmt
::
memory_buffer
&
dest
)
{
#ifndef SPDLOG_NO_DATETIME
auto
secs
=
std
::
chrono
::
duration_cast
<
std
::
chrono
::
seconds
>
(
msg
.
time
.
time_since_epoch
());
if
(
secs
!=
last_log_secs_
)
{
cached_tm_
=
get_time_
(
msg
);
last_log_secs_
=
secs
;
}
#endif
for
(
auto
&
f
:
formatters_
)
{
f
->
format
(
msg
,
cached_tm_
,
dest
);
}
// write eol
details
::
fmt_helper
::
append_string_view
(
eol_
,
dest
);
}
std
::
tm
pattern_formatter
::
get_time_
(
const
details
::
log_msg
&
msg
)
{
if
(
pattern_time_type_
==
pattern_time_type
::
local
)
{
return
details
::
os
::
localtime
(
log_clock
::
to_time_t
(
msg
.
time
));
}
return
details
::
os
::
gmtime
(
log_clock
::
to_time_t
(
msg
.
time
));
}
void
pattern_formatter
::
handle_flag_
(
char
flag
,
details
::
padding_info
padding
)
{
switch
(
flag
)
{
case
(
'+'
):
// default formatter
formatters_
.
push_back
(
details
::
make_unique
<
details
::
full_formatter
>
(
padding
));
break
;
case
'n'
:
// logger name
formatters_
.
push_back
(
details
::
make_unique
<
details
::
name_formatter
>
(
padding
));
break
;
case
'l'
:
// level
formatters_
.
push_back
(
details
::
make_unique
<
details
::
level_formatter
>
(
padding
));
break
;
case
'L'
:
// short level
formatters_
.
push_back
(
details
::
make_unique
<
details
::
short_level_formatter
>
(
padding
));
break
;
case
(
't'
):
// thread id
formatters_
.
push_back
(
details
::
make_unique
<
details
::
t_formatter
>
(
padding
));
break
;
case
(
'v'
):
// the message text
formatters_
.
push_back
(
details
::
make_unique
<
details
::
v_formatter
>
(
padding
));
break
;
case
(
'a'
):
// weekday
formatters_
.
push_back
(
details
::
make_unique
<
details
::
a_formatter
>
(
padding
));
break
;
case
(
'A'
):
// short weekday
formatters_
.
push_back
(
details
::
make_unique
<
details
::
A_formatter
>
(
padding
));
break
;
case
(
'b'
):
case
(
'h'
):
// month
formatters_
.
push_back
(
details
::
make_unique
<
details
::
b_formatter
>
(
padding
));
break
;
case
(
'B'
):
// short month
formatters_
.
push_back
(
details
::
make_unique
<
details
::
B_formatter
>
(
padding
));
break
;
case
(
'c'
):
// datetime
formatters_
.
push_back
(
details
::
make_unique
<
details
::
c_formatter
>
(
padding
));
break
;
case
(
'C'
):
// year 2 digits
formatters_
.
push_back
(
details
::
make_unique
<
details
::
C_formatter
>
(
padding
));
break
;
case
(
'Y'
):
// year 4 digits
formatters_
.
push_back
(
details
::
make_unique
<
details
::
Y_formatter
>
(
padding
));
break
;
case
(
'D'
):
case
(
'x'
):
// datetime MM/DD/YY
formatters_
.
push_back
(
details
::
make_unique
<
details
::
D_formatter
>
(
padding
));
break
;
case
(
'm'
):
// month 1-12
formatters_
.
push_back
(
details
::
make_unique
<
details
::
m_formatter
>
(
padding
));
break
;
case
(
'd'
):
// day of month 1-31
formatters_
.
push_back
(
details
::
make_unique
<
details
::
d_formatter
>
(
padding
));
break
;
case
(
'H'
):
// hours 24
formatters_
.
push_back
(
details
::
make_unique
<
details
::
H_formatter
>
(
padding
));
break
;
case
(
'I'
):
// hours 12
formatters_
.
push_back
(
details
::
make_unique
<
details
::
I_formatter
>
(
padding
));
break
;
case
(
'M'
):
// minutes
formatters_
.
push_back
(
details
::
make_unique
<
details
::
M_formatter
>
(
padding
));
break
;
case
(
'S'
):
// seconds
formatters_
.
push_back
(
details
::
make_unique
<
details
::
S_formatter
>
(
padding
));
break
;
case
(
'e'
):
// milliseconds
formatters_
.
push_back
(
details
::
make_unique
<
details
::
e_formatter
>
(
padding
));
break
;
case
(
'f'
):
// microseconds
formatters_
.
push_back
(
details
::
make_unique
<
details
::
f_formatter
>
(
padding
));
break
;
case
(
'F'
):
// nanoseconds
formatters_
.
push_back
(
details
::
make_unique
<
details
::
F_formatter
>
(
padding
));
break
;
case
(
'E'
):
// seconds since epoch
formatters_
.
push_back
(
details
::
make_unique
<
details
::
E_formatter
>
(
padding
));
break
;
case
(
'p'
):
// am/pm
formatters_
.
push_back
(
details
::
make_unique
<
details
::
p_formatter
>
(
padding
));
break
;
case
(
'r'
):
// 12 hour clock 02:55:02 pm
formatters_
.
push_back
(
details
::
make_unique
<
details
::
r_formatter
>
(
padding
));
break
;
case
(
'R'
):
// 24-hour HH:MM time
formatters_
.
push_back
(
details
::
make_unique
<
details
::
R_formatter
>
(
padding
));
break
;
case
(
'T'
):
case
(
'X'
):
// ISO 8601 time format (HH:MM:SS)
formatters_
.
push_back
(
details
::
make_unique
<
details
::
T_formatter
>
(
padding
));
break
;
case
(
'z'
):
// timezone
formatters_
.
push_back
(
details
::
make_unique
<
details
::
z_formatter
>
(
padding
));
break
;
case
(
'P'
):
// pid
formatters_
.
push_back
(
details
::
make_unique
<
details
::
pid_formatter
>
(
padding
));
break
;
case
(
'^'
):
// color range start
formatters_
.
push_back
(
details
::
make_unique
<
details
::
color_start_formatter
>
(
padding
));
break
;
case
(
'$'
):
// color range end
formatters_
.
push_back
(
details
::
make_unique
<
details
::
color_stop_formatter
>
(
padding
));
break
;
case
(
'@'
):
// source location (filename:filenumber)
formatters_
.
push_back
(
details
::
make_unique
<
details
::
source_location_formatter
>
(
padding
));
break
;
case
(
's'
):
// source filename
formatters_
.
push_back
(
details
::
make_unique
<
details
::
source_filename_formatter
>
(
padding
));
break
;
case
(
'#'
):
// source line number
formatters_
.
push_back
(
details
::
make_unique
<
details
::
source_linenum_formatter
>
(
padding
));
break
;
case
(
'!'
):
// source funcname
formatters_
.
push_back
(
details
::
make_unique
<
details
::
source_funcname_formatter
>
(
padding
));
break
;
case
(
'%'
):
// % char
formatters_
.
push_back
(
details
::
make_unique
<
details
::
ch_formatter
>
(
'%'
));
break
;
default
:
// Unknown flag appears as is
auto
unknown_flag
=
details
::
make_unique
<
details
::
aggregate_formatter
>
();
unknown_flag
->
add_ch
(
'%'
);
unknown_flag
->
add_ch
(
flag
);
formatters_
.
push_back
((
std
::
move
(
unknown_flag
)));
break
;
}
}
// Extract given pad spec (e.g. %8X)
// Advance the given it pass the end of the padding spec found (if any)
// Return padding.
details
::
padding_info
pattern_formatter
::
handle_padspec_
(
std
::
string
::
const_iterator
&
it
,
std
::
string
::
const_iterator
end
)
{
using
details
::
padding_info
;
using
details
::
scoped_pad
;
const
size_t
max_width
=
128
;
if
(
it
==
end
)
{
return
padding_info
{};
}
padding_info
::
pad_side
side
;
switch
(
*
it
)
{
case
'-'
:
side
=
padding_info
::
right
;
++
it
;
break
;
case
'='
:
side
=
padding_info
::
center
;
++
it
;
break
;
default
:
side
=
details
::
padding_info
::
left
;
break
;
}
if
(
it
==
end
||
!
std
::
isdigit
(
static_cast
<
unsigned
char
>
(
*
it
)))
{
return
padding_info
{
0
,
side
};
}
auto
width
=
static_cast
<
size_t
>
(
*
it
-
'0'
);
for
(
++
it
;
it
!=
end
&&
std
::
isdigit
(
static_cast
<
unsigned
char
>
(
*
it
));
++
it
)
{
auto
digit
=
static_cast
<
size_t
>
(
*
it
-
'0'
);
width
=
width
*
10
+
digit
;
}
return
details
::
padding_info
{
std
::
min
<
size_t
>
(
width
,
max_width
),
side
};
}
void
pattern_formatter
::
compile_pattern_
(
const
std
::
string
&
pattern
)
{
auto
end
=
pattern
.
end
();
std
::
unique_ptr
<
details
::
aggregate_formatter
>
user_chars
;
formatters_
.
clear
();
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
));
}
auto
padding
=
handle_padspec_
(
++
it
,
end
);
if
(
it
!=
end
)
{
handle_flag_
(
*
it
,
padding
);
}
else
{
break
;
}
}
else
// chars not following the % sign should be displayed as is
{
if
(
!
user_chars
)
{
user_chars
=
details
::
make_unique
<
details
::
aggregate_formatter
>
();
}
user_chars
->
add_ch
(
*
it
);
}
}
if
(
user_chars
)
// append raw chars found so far
{
formatters_
.
push_back
(
std
::
move
(
user_chars
));
}
}
}
// namespace spdlog
tests/includes.h
View file @
17f9cdd4
...
...
@@ -11,7 +11,6 @@
#include <string>
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
#define SPDLOG_ENABLE_MESSAGE_COUNTER
#include "spdlog/spdlog.h"
#include "spdlog/async.h"
...
...
tests/test_errors.cpp
View file @
17f9cdd4
...
...
@@ -41,13 +41,18 @@ TEST_CASE("default_error_handler", "[errors]]")
struct
custom_ex
{
};
static
void
custom_handler
(
const
std
::
string
&
msg
)
{
throw
custom_ex
();
}
TEST_CASE
(
"custom_error_handler"
,
"[errors]]"
)
{
prepare_logdir
();
std
::
string
filename
=
"logs/simple_log.txt"
;
auto
logger
=
spdlog
::
create
<
spdlog
::
sinks
::
basic_file_sink_mt
>
(
"logger"
,
filename
,
true
);
logger
->
flush_on
(
spdlog
::
level
::
info
);
logger
->
set_error_handler
(
[
=
](
const
std
::
string
&
)
{
throw
custom_ex
();
}
);
logger
->
set_error_handler
(
custom_handler
);
logger
->
info
(
"Good message #1"
);
REQUIRE_THROWS_AS
(
logger
->
info
(
"Bad format msg {} {}"
,
"xxx"
),
custom_ex
);
...
...
@@ -59,7 +64,7 @@ TEST_CASE("default_error_handler2", "[errors]]")
{
spdlog
::
drop_all
();
auto
logger
=
spdlog
::
create
<
failing_sink
>
(
"failed_logger"
);
logger
->
set_error_handler
(
[
=
](
const
std
::
string
&
)
{
throw
custom_ex
();
}
);
logger
->
set_error_handler
(
custom_handler
);
REQUIRE_THROWS_AS
(
logger
->
info
(
"Some message"
),
custom_ex
);
}
...
...
@@ -67,26 +72,26 @@ TEST_CASE("flush_error_handler", "[errors]]")
{
spdlog
::
drop_all
();
auto
logger
=
spdlog
::
create
<
failing_sink
>
(
"failed_logger"
);
logger
->
set_error_handler
(
[
=
](
const
std
::
string
&
)
{
throw
custom_ex
();
}
);
logger
->
set_error_handler
(
custom_handler
);
REQUIRE_THROWS_AS
(
logger
->
flush
(),
custom_ex
);
}
TEST_CASE
(
"async_error_handler"
,
"[errors]]"
)
{
prepare_logdir
();
std
::
string
err_msg
(
"log failed with some msg"
);
std
::
string
filename
=
"logs/simple_async_log.txt"
;
{
spdlog
::
init_thread_pool
(
128
,
1
);
auto
logger
=
spdlog
::
create_async
<
spdlog
::
sinks
::
basic_file_sink_mt
>
(
"logger"
,
filename
,
true
);
logger
->
set_error_handler
([
=
](
const
std
::
string
&
)
{
logger
->
set_error_handler
([](
const
std
::
string
&
)
{
std
::
ofstream
ofs
(
"logs/custom_err.txt"
);
if
(
!
ofs
)
{
throw
std
::
runtime_error
(
"Failed open logs/custom_err.txt"
);
}
ofs
<<
err_msg
;
ofs
<<
"log failed with some msg"
;
});
logger
->
info
(
"Good message #1"
);
logger
->
info
(
"Bad format msg {} {}"
,
"xxx"
);
...
...
@@ -95,27 +100,26 @@ TEST_CASE("async_error_handler", "[errors]]")
}
spdlog
::
init_thread_pool
(
128
,
1
);
REQUIRE
(
count_lines
(
filename
)
==
2
);
REQUIRE
(
file_contents
(
"logs/custom_err.txt"
)
==
err_msg
);
REQUIRE
(
file_contents
(
"logs/custom_err.txt"
)
==
"log failed with some msg"
);
}
// Make sure async error handler is executed
TEST_CASE
(
"async_error_handler2"
,
"[errors]]"
)
{
prepare_logdir
();
std
::
string
err_msg
(
"This is async handler error message"
);
{
spdlog
::
init_thread_pool
(
128
,
1
);
auto
logger
=
spdlog
::
create_async
<
failing_sink
>
(
"failed_logger"
);
logger
->
set_error_handler
([
=
](
const
std
::
string
&
)
{
logger
->
set_error_handler
([](
const
std
::
string
&
)
{
std
::
ofstream
ofs
(
"logs/custom_err2.txt"
);
if
(
!
ofs
)
throw
std
::
runtime_error
(
"Failed open logs/custom_err2.txt"
);
ofs
<<
err_msg
;
ofs
<<
"handler error message"
;
});
logger
->
info
(
"Hello failure"
);
spdlog
::
drop
(
"failed_logger"
);
// force logger to drain the queue and shutdown
}
spdlog
::
init_thread_pool
(
128
,
1
);
REQUIRE
(
file_contents
(
"logs/custom_err2.txt"
)
==
err_msg
);
REQUIRE
(
file_contents
(
"logs/custom_err2.txt"
)
==
"handler error message"
);
}
tests/test_misc.cpp
View file @
17f9cdd4
...
...
@@ -107,7 +107,6 @@ TEST_CASE("clone-logger", "[clone]")
cloned
->
info
(
"Some message 2"
);
auto
test_sink
=
std
::
static_pointer_cast
<
sinks
::
test_sink_mt
>
(
cloned
->
sinks
()[
0
]);
REQUIRE
(
test_sink
->
msg_counter
()
==
2
);
spdlog
::
drop_all
();
}
...
...
@@ -130,7 +129,6 @@ TEST_CASE("clone async", "[clone]")
spdlog
::
details
::
os
::
sleep_for_millis
(
10
);
auto
test_sink
=
std
::
static_pointer_cast
<
sinks
::
test_sink_mt
>
(
cloned
->
sinks
()[
0
]);
REQUIRE
(
test_sink
->
msg_counter
()
==
2
);
spdlog
::
drop_all
();
}
...
...
@@ -176,22 +174,6 @@ TEST_CASE("to_hex_no_delimiter", "[to_hex]")
REQUIRE
(
ends_with
(
output
,
"0000: 090A0B0CFFFF"
+
std
::
string
(
spdlog
::
details
::
os
::
default_eol
)));
}
TEST_CASE
(
"message_counter"
,
"[message_counter]"
)
{
std
::
ostringstream
oss
;
auto
oss_sink
=
std
::
make_shared
<
spdlog
::
sinks
::
ostream_sink_mt
>
(
oss
);
spdlog
::
logger
oss_logger
(
"oss"
,
oss_sink
);
oss_logger
.
set_pattern
(
"%i %v"
);
oss_logger
.
info
(
"Hello"
);
REQUIRE
(
oss
.
str
()
==
"000001 Hello"
+
std
::
string
(
spdlog
::
details
::
os
::
default_eol
));
oss
.
str
(
""
);
oss_logger
.
info
(
"Hello again"
);
REQUIRE
(
oss
.
str
()
==
"000002 Hello again"
+
std
::
string
(
spdlog
::
details
::
os
::
default_eol
));
}
TEST_CASE
(
"default logger API"
,
"[default logger]"
)
{
std
::
ostringstream
oss
;
...
...
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