Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
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
Operations
Operations
Metrics
Environments
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
cpp-libs
Actor Framework
Commits
168a2a2b
Unverified
Commit
168a2a2b
authored
Nov 21, 2018
by
Joseph Noir
Committed by
GitHub
Nov 21, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #797
Limit maximum memory consumption of the logger
parents
f52cf24f
af5eb9d3
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
612 additions
and
342 deletions
+612
-342
CMakeLists.txt
CMakeLists.txt
+5
-19
Jenkinsfile
Jenkinsfile
+1
-1
cmake/build_config.hpp.in
cmake/build_config.hpp.in
+3
-1
configure
configure
+1
-22
libcaf_core/caf/atom.hpp
libcaf_core/caf/atom.hpp
+4
-0
libcaf_core/caf/detail/log_level.hpp
libcaf_core/caf/detail/log_level.hpp
+37
-0
libcaf_core/caf/detail/ringbuffer.hpp
libcaf_core/caf/detail/ringbuffer.hpp
+117
-0
libcaf_core/caf/logger.hpp
libcaf_core/caf/logger.hpp
+201
-154
libcaf_core/src/atom.cpp
libcaf_core/src/atom.cpp
+38
-15
libcaf_core/src/logger.cpp
libcaf_core/src/logger.cpp
+104
-129
libcaf_core/test/logger.cpp
libcaf_core/test/logger.cpp
+1
-1
libcaf_core/test/ringbuffer.cpp
libcaf_core/test/ringbuffer.cpp
+100
-0
No files found.
CMakeLists.txt
View file @
168a2a2b
...
@@ -367,8 +367,11 @@ endif()
...
@@ -367,8 +367,11 @@ endif()
# setup logging #
# setup logging #
################################################################################
################################################################################
# make sure log level is defined and all-uppercase
if
(
NOT CAF_LOG_LEVEL
)
if
(
NOT CAF_LOG_LEVEL
)
set
(
CAF_LOG_LEVEL
"-1"
)
set
(
CAF_LOG_LEVEL
"QUIET"
)
else
()
string
(
TOUPPER
"
${
CAF_LOG_LEVEL
}
"
CAF_LOG_LEVEL
)
endif
()
endif
()
################################################################################
################################################################################
...
@@ -662,23 +665,6 @@ add_custom_target(gui_dummy SOURCES configure ${script_files})
...
@@ -662,23 +665,6 @@ add_custom_target(gui_dummy SOURCES configure ${script_files})
# print summary #
# print summary #
################################################################################
################################################################################
# set human-readable representation for log level
set
(
LOG_LEVEL_STR
"none"
)
if
(
CAF_LOG_LEVEL
)
if
(
${
CAF_LOG_LEVEL
}
EQUAL 0
)
set
(
LOG_LEVEL_STR
"ERROR"
)
elseif
(
${
CAF_LOG_LEVEL
}
EQUAL 1
)
set
(
LOG_LEVEL_STR
"WARNING"
)
elseif
(
${
CAF_LOG_LEVEL
}
EQUAL 2
)
set
(
LOG_LEVEL_STR
"INFO"
)
elseif
(
${
CAF_LOG_LEVEL
}
EQUAL 3
)
set
(
LOG_LEVEL_STR
"DEBUG"
)
elseif
(
${
CAF_LOG_LEVEL
}
EQUAL 4
)
set
(
LOG_LEVEL_STR
"TRACE"
)
else
()
set
(
LOG_LEVEL_STR
"invalid"
)
endif
()
endif
()
# little helper macro to invert a boolean
# little helper macro to invert a boolean
macro
(
invertYesNo in out
)
macro
(
invertYesNo in out
)
if
(
${
in
}
)
if
(
${
in
}
)
...
@@ -715,7 +701,7 @@ if(NOT CAF_NO_SUMMARY)
...
@@ -715,7 +701,7 @@ if(NOT CAF_NO_SUMMARY)
"
\n
Build static only:
${
CAF_BUILD_STATIC_ONLY
}
"
"
\n
Build static only:
${
CAF_BUILD_STATIC_ONLY
}
"
"
\n
Build static runtime:
${
CAF_BUILD_STATIC_RUNTIME
}
"
"
\n
Build static runtime:
${
CAF_BUILD_STATIC_RUNTIME
}
"
"
\n
Runtime checks:
${
CAF_ENABLE_RUNTIME_CHECKS
}
"
"
\n
Runtime checks:
${
CAF_ENABLE_RUNTIME_CHECKS
}
"
"
\n
Log level:
${
LOG_LEVEL_STR
}
"
"
\n
Log level:
${
CAF_LOG_LEVEL
}
"
"
\n
With mem. mgmt.:
${
CAF_BUILD_MEM_MANAGEMENT
}
"
"
\n
With mem. mgmt.:
${
CAF_BUILD_MEM_MANAGEMENT
}
"
"
\n
With exceptions:
${
CAF_BUILD_WITH_EXCEPTIONS
}
"
"
\n
With exceptions:
${
CAF_BUILD_WITH_EXCEPTIONS
}
"
"
\n
"
"
\n
"
...
...
Jenkinsfile
View file @
168a2a2b
...
@@ -17,7 +17,7 @@ releaseBuildFlags = defaultBuildFlags + [
...
@@ -17,7 +17,7 @@ releaseBuildFlags = defaultBuildFlags + [
debugBuildFlags
=
defaultBuildFlags
+
[
debugBuildFlags
=
defaultBuildFlags
+
[
'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes'
,
'CAF_ENABLE_RUNTIME_CHECKS:BOOL=yes'
,
'CAF_ENABLE_ADDRESS_SANITIZER:BOOL=yes'
,
'CAF_ENABLE_ADDRESS_SANITIZER:BOOL=yes'
,
'CAF_LOG_LEVEL:STRING=
4
'
,
'CAF_LOG_LEVEL:STRING=
TRACE
'
,
]
]
// Our build matrix. The keys are the operating system labels and the values
// Our build matrix. The keys are the operating system labels and the values
...
...
cmake/build_config.hpp.in
View file @
168a2a2b
...
@@ -19,9 +19,11 @@
...
@@ -19,9 +19,11 @@
#pragma once
#pragma once
#include "caf/detail/log_level.hpp"
// this header is auto-generated by CMake
// this header is auto-generated by CMake
#define CAF_LOG_LEVEL @CAF_LOG_LEVEL@
#define CAF_LOG_LEVEL
CAF_LOG_LEVEL_
@CAF_LOG_LEVEL@
#cmakedefine CAF_NO_MEM_MANAGEMENT
#cmakedefine CAF_NO_MEM_MANAGEMENT
...
...
configure
View file @
168a2a2b
...
@@ -284,28 +284,7 @@ while [ $# -ne 0 ]; do
...
@@ -284,28 +284,7 @@ while [ $# -ne 0 ]; do
append_cache_entry CAF_IOS_DEPLOYMENT_TARGET STRING
"
$optarg
"
append_cache_entry CAF_IOS_DEPLOYMENT_TARGET STRING
"
$optarg
"
;;
;;
--with-log-level
=
*
)
--with-log-level
=
*
)
level
=
`
echo
"
$optarg
"
|
tr
'[:lower:]'
'[:upper:]'
`
append_cache_entry CAF_LOG_LEVEL STRING
"
$optarg
"
case
$level
in
ERROR
)
append_cache_entry CAF_LOG_LEVEL STRING 0
;;
WARNING
)
append_cache_entry CAF_LOG_LEVEL STRING 1
;;
INFO
)
append_cache_entry CAF_LOG_LEVEL STRING 2
;;
DEBUG
)
append_cache_entry CAF_LOG_LEVEL STRING 3
;;
TRACE
)
append_cache_entry CAF_LOG_LEVEL STRING 4
;;
*
)
echo
"Invalid log level '
$level
'. Try '
$0
--help' to see valid values."
exit
1
;;
esac
;;
;;
--with-clang
=
*
)
--with-clang
=
*
)
clang
=
"
$optarg
"
clang
=
"
$optarg
"
...
...
libcaf_core/caf/atom.hpp
View file @
168a2a2b
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#include <type_traits>
#include <type_traits>
#include "caf/detail/atom_val.hpp"
#include "caf/detail/atom_val.hpp"
#include "caf/fwd.hpp"
namespace
caf
{
namespace
caf
{
...
@@ -36,6 +37,9 @@ enum class atom_value : uint64_t {
...
@@ -36,6 +37,9 @@ enum class atom_value : uint64_t {
/// @relates atom_value
/// @relates atom_value
std
::
string
to_string
(
const
atom_value
&
what
);
std
::
string
to_string
(
const
atom_value
&
what
);
/// @relates atom_value
atom_value
to_lowercase
(
atom_value
x
);
atom_value
atom_from_string
(
const
std
::
string
&
x
);
atom_value
atom_from_string
(
const
std
::
string
&
x
);
/// Creates an atom from given string literal.
/// Creates an atom from given string literal.
...
...
libcaf_core/caf/detail/log_level.hpp
0 → 100644
View file @
168a2a2b
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
/// Integer value for the QUIET log level.
#define CAF_LOG_LEVEL_QUIET 0
/// Integer value for the ERROR log level.
#define CAF_LOG_LEVEL_ERROR 3
/// Integer value for the WARNING log level.
#define CAF_LOG_LEVEL_WARNING 6
/// Integer value for the INFO log level.
#define CAF_LOG_LEVEL_INFO 9
/// Integer value for the DEBUG log level.
#define CAF_LOG_LEVEL_DEBUG 12
/// Integer value for the TRACE log level.
#define CAF_LOG_LEVEL_TRACE 15
libcaf_core/caf/detail/ringbuffer.hpp
0 → 100644
View file @
168a2a2b
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <array>
#include <atomic>
#include <condition_variable>
#include <mutex>
namespace
caf
{
namespace
detail
{
// A ringbuffer designed for a single consumer and any number of producers that
// can hold a maximum of `Size - 1` elements.
template
<
class
T
,
size_t
Size
>
class
ringbuffer
{
public:
using
guard_type
=
std
::
unique_lock
<
std
::
mutex
>
;
ringbuffer
()
:
wr_pos_
(
0
),
rd_pos_
(
0
)
{
// nop
}
void
wait_nonempty
()
{
// Double-checked locking to reduce contention on mtx_.
if
(
!
empty
())
return
;
guard_type
guard
{
mtx_
};
while
(
empty
())
cv_empty_
.
wait
(
guard
);
}
T
&
front
()
{
// Safe to access without lock, because we assume a single consumer.
return
buf_
[
rd_pos_
];
}
void
pop_front
()
{
guard_type
guard
{
mtx_
};
auto
rp
=
rd_pos_
.
load
();
rd_pos_
=
next
(
rp
);
// Wakeup a waiting producers if the queue became non-full.
if
(
rp
==
next
(
wr_pos_
))
cv_full_
.
notify_all
();
}
void
push_back
(
T
&&
x
)
{
guard_type
guard
{
mtx_
};
while
(
full
())
cv_full_
.
wait
(
guard
);
auto
wp
=
wr_pos_
.
load
();
buf_
[
wp
]
=
std
::
move
(
x
);
wr_pos_
=
next
(
wp
);
if
(
rd_pos_
==
wp
)
cv_empty_
.
notify_all
();
}
bool
empty
()
const
noexcept
{
return
rd_pos_
==
wr_pos_
;
}
bool
full
()
const
noexcept
{
return
rd_pos_
==
next
(
wr_pos_
);
}
size_t
size
()
const
noexcept
{
auto
rp
=
rd_pos_
.
load
();
auto
wp
=
wr_pos_
.
load
();
if
(
rp
==
wp
)
return
0
;
if
(
rp
<
wp
)
return
wp
-
rp
;
return
Size
-
rp
+
wp
;
}
private:
static
size_t
next
(
size_t
pos
)
{
return
(
pos
+
1
)
%
Size
;
}
// Guards queue_.
mutable
std
::
mutex
mtx_
;
// Signals the empty condition.
std
::
condition_variable
cv_empty_
;
// Signals the full condition.
std
::
condition_variable
cv_full_
;
// Stores the current write position in the ringbuffer.
std
::
atomic
<
size_t
>
wr_pos_
;
// Stores the current read position in the ringbuffer.
std
::
atomic
<
size_t
>
rd_pos_
;
// Stores events in a circular ringbuffer.
std
::
array
<
T
,
Size
>
buf_
;
};
}
// namespace detail
}
// namespace caf
libcaf_core/caf/logger.hpp
View file @
168a2a2b
...
@@ -30,22 +30,21 @@
...
@@ -30,22 +30,21 @@
#include "caf/abstract_actor.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/config.hpp"
#include "caf/config.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/deep_to_string.hpp"
#include "caf/detail/arg_wrapper.hpp"
#include "caf/detail/pretty_type_name.hpp"
#include "caf/detail/ringbuffer.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/detail/shared_spinlock.hpp"
#include "caf/fwd.hpp"
#include "caf/fwd.hpp"
#include "caf/intrusive/drr_queue.hpp"
#include "caf/intrusive/fifo_inbox.hpp"
#include "caf/intrusive/singly_linked.hpp"
#include "caf/ref_counted.hpp"
#include "caf/ref_counted.hpp"
#include "caf/string_view.hpp"
#include "caf/string_view.hpp"
#include "caf/timestamp.hpp"
#include "caf/timestamp.hpp"
#include "caf/type_nr.hpp"
#include "caf/type_nr.hpp"
#include "caf/unifyn.hpp"
#include "caf/unifyn.hpp"
#include "caf/intrusive/drr_queue.hpp"
#include "caf/intrusive/fifo_inbox.hpp"
#include "caf/intrusive/singly_linked.hpp"
#include "caf/detail/arg_wrapper.hpp"
#include "caf/detail/pretty_type_name.hpp"
#include "caf/detail/scope_guard.hpp"
#include "caf/detail/shared_spinlock.hpp"
/*
/*
* To enable logging, you have to define CAF_DEBUG. This enables
* To enable logging, you have to define CAF_DEBUG. This enables
* CAF_LOG_ERROR messages. To enable more debugging output, you can
* CAF_LOG_ERROR messages. To enable more debugging output, you can
...
@@ -66,18 +65,64 @@ namespace caf {
...
@@ -66,18 +65,64 @@ namespace caf {
/// default, the logger generates log4j compatible output.
/// default, the logger generates log4j compatible output.
class
logger
:
public
ref_counted
{
class
logger
:
public
ref_counted
{
public:
public:
// -- friends ----------------------------------------------------------------
friend
class
actor_system
;
friend
class
actor_system
;
// -- constants --------------------------------------------------------------
/// Configures the size of the circular event queue.
static
constexpr
size_t
queue_size
=
128
;
// -- member types -----------------------------------------------------------
/// Combines various logging-related flags and parameters into a bitfield.
struct
config
{
/// Stores `max(file_verbosity, console_verbosity)`.
unsigned
verbosity
:
4
;
/// Configures the verbosity for file output.
unsigned
file_verbosity
:
4
;
/// Configures the verbosity for console output.
unsigned
console_verbosity
:
4
;
/// Configures whether the logger immediately writes its output in the
/// calling thread, bypassing its queue. Use this option only in
/// single-threaded test environments.
bool
inline_output
:
1
;
/// Configures whether the logger generates colored output.
bool
console_coloring
:
1
;
config
();
};
/// Encapsulates a single logging event.
/// Encapsulates a single logging event.
struct
event
:
intrusive
::
singly_linked
<
event
>
{
struct
event
{
// -- constructors, destructors, and assignment operators ------------------
event
()
=
default
;
event
()
=
default
;
event
(
int
lvl
,
string_view
cat
,
string_view
full_fun
,
string_view
fun
,
event
(
event
&&
)
=
default
;
string_view
fn
,
int
line
,
std
::
string
msg
,
std
::
thread
::
id
t
,
event
(
const
event
&
)
=
default
;
event
&
operator
=
(
event
&&
)
=
default
;
event
&
operator
=
(
const
event
&
)
=
default
;
event
(
unsigned
lvl
,
unsigned
line
,
string_view
cat
,
string_view
full_fun
,
string_view
fun
,
string_view
fn
,
std
::
string
msg
,
std
::
thread
::
id
t
,
actor_id
a
,
timestamp
ts
);
actor_id
a
,
timestamp
ts
);
// -- member variables -----------------------------------------------------
/// Level/priority of the event.
/// Level/priority of the event.
int
level
;
unsigned
level
;
/// Current line in the file.
unsigned
line_number
;
/// Name of the category (component) logging the event.
/// Name of the category (component) logging the event.
string_view
category_name
;
string_view
category_name
;
...
@@ -91,9 +136,6 @@ public:
...
@@ -91,9 +136,6 @@ public:
/// Name of the current file.
/// Name of the current file.
string_view
file_name
;
string_view
file_name
;
/// Current line in the file.
int
line_number
;
/// User-provided message.
/// User-provided message.
std
::
string
message
;
std
::
string
message
;
...
@@ -107,37 +149,6 @@ public:
...
@@ -107,37 +149,6 @@ public:
timestamp
tstamp
;
timestamp
tstamp
;
};
};
struct
policy
{
// -- member types ---------------------------------------------------------
using
mapped_type
=
event
;
using
task_size_type
=
long
;
using
deleter_type
=
std
::
default_delete
<
event
>
;
using
unique_pointer
=
std
::
unique_ptr
<
event
,
deleter_type
>
;
using
queue_type
=
intrusive
::
drr_queue
<
policy
>
;
using
deficit_type
=
long
;
// -- static member functions ----------------------------------------------
static
inline
void
release
(
mapped_type
*
ptr
)
noexcept
{
detail
::
disposer
d
;
d
(
ptr
);
}
static
inline
task_size_type
task_size
(
const
mapped_type
&
)
noexcept
{
return
1
;
}
static
inline
deficit_type
quantum
(
const
queue_type
&
,
deficit_type
x
)
{
return
x
;
}
};
/// Internal representation of format string entites.
/// Internal representation of format string entites.
enum
field_type
{
enum
field_type
{
invalid_field
,
invalid_field
,
...
@@ -196,37 +207,52 @@ public:
...
@@ -196,37 +207,52 @@ public:
std
::
string
str_
;
std
::
string
str_
;
};
};
/// Returns the ID of the actor currently associated to the calling thread.
// -- constructors, destructors, and assignment operators --------------------
actor_id
thread_local_aid
();
/// Associates an actor ID to the calling thread and returns the last value.
actor_id
thread_local_aid
(
actor_id
aid
);
/// Writes an entry to the log file.
void
log
(
event
*
x
);
~
logger
()
override
;
~
logger
()
override
;
/
** @cond PRIVATE */
/
/ -- logging ----------------------------------------------------------------
static
void
set_current_actor_system
(
actor_system
*
);
/// Writes an entry to the event-queue of the logger.
/// @thread-safe
void
log
(
event
&&
x
);
static
logger
*
current_logger
();
// -- properties -------------------------------------------------------------
/// Returns the ID of the actor currently associated to the calling thread.
actor_id
thread_local_aid
();
bool
accepts
(
int
level
,
string_view
cname
);
/// Associates an actor ID to the calling thread and returns the last value.
actor_id
thread_local_aid
(
actor_id
aid
);
/** @endcond */
/// Returns whether the logger is configured to accept input for given
/// component and log level.
bool
accepts
(
unsigned
level
,
string_view
component_name
);
/// Returns the output format used for the log file.
/// Returns the output format used for the log file.
inline
const
line_format
&
file_format
()
const
{
const
line_format
&
file_format
()
const
{
return
file_format_
;
return
file_format_
;
}
}
/// Returns the output format used for the console.
/// Returns the output format used for the console.
inline
const
line_format
&
console_format
()
const
{
const
line_format
&
console_format
()
const
{
return
console_format_
;
return
console_format_
;
}
}
unsigned
verbosity
()
const
noexcept
{
return
cfg_
.
verbosity
;
}
unsigned
file_verbosity
()
const
noexcept
{
return
cfg_
.
file_verbosity
;
}
unsigned
console_verbosity
()
const
noexcept
{
return
cfg_
.
console_verbosity
;
}
// -- static utility functions -----------------------------------------------
/// Renders the prefix (namespace and class) of a fully qualified function.
/// Renders the prefix (namespace and class) of a fully qualified function.
static
void
render_fun_prefix
(
std
::
ostream
&
out
,
const
event
&
x
);
static
void
render_fun_prefix
(
std
::
ostream
&
out
,
const
event
&
x
);
...
@@ -239,9 +265,6 @@ public:
...
@@ -239,9 +265,6 @@ public:
/// Renders the date of `x` in ISO 8601 format.
/// Renders the date of `x` in ISO 8601 format.
static
void
render_date
(
std
::
ostream
&
out
,
timestamp
x
);
static
void
render_date
(
std
::
ostream
&
out
,
timestamp
x
);
/// Renders `x` using the line format `lf` to `out`.
void
render
(
std
::
ostream
&
out
,
const
line_format
&
lf
,
const
event
&
x
)
const
;
/// Parses `format_str` into a format description vector.
/// Parses `format_str` into a format description vector.
/// @warning The returned vector can have pointers into `format_str`.
/// @warning The returned vector can have pointers into `format_str`.
static
line_format
parse_format
(
const
std
::
string
&
format_str
);
static
line_format
parse_format
(
const
std
::
string
&
format_str
);
...
@@ -249,6 +272,11 @@ public:
...
@@ -249,6 +272,11 @@ public:
/// Skips path in `filename`.
/// Skips path in `filename`.
static
string_view
skip_path
(
string_view
filename
);
static
string_view
skip_path
(
string_view
filename
);
// -- utility functions ------------------------------------------------------
/// Renders `x` using the line format `lf` to `out`.
void
render
(
std
::
ostream
&
out
,
const
line_format
&
lf
,
const
event
&
x
)
const
;
/// Returns a string representation of the joined groups of `x` if `x` is an
/// Returns a string representation of the joined groups of `x` if `x` is an
/// actor with the `subscriber` mixin.
/// actor with the `subscriber` mixin.
template
<
class
T
>
template
<
class
T
>
...
@@ -272,30 +300,37 @@ public:
...
@@ -272,30 +300,37 @@ public:
return
"[]"
;
return
"[]"
;
}
}
// -- individual flags -------------------------------------------------------
// -- thread-local properties ------------------------------------------------
/// Stores the actor system for the current thread.
static
void
set_current_actor_system
(
actor_system
*
);
/// Returns the logger for the current thread or `nullptr` if none is
/// registered.
static
logger
*
current_logger
();
static
constexpr
int
inline_output_flag
=
0x01
;
private:
// -- constructors, destructors, and assignment operators --------------------
static
constexpr
int
uncolored_console_flag
=
0x02
;
logger
(
actor_system
&
sys
)
;
static
constexpr
int
colored_console_flag
=
0x04
;
// -- initialization ---------------------------------------------------------
// -- composed flags ---------------------------------------------------------
void
init
(
actor_system_config
&
cfg
);
static
constexpr
int
console_output_flag
=
0x06
;
// -- event handling ---------------------------------------------------------
private:
void
handle_event
(
const
event
&
x
);
void
handle_event
(
event
&
x
);
void
handle_file_event
(
event
&
x
);
void
handle_file_event
(
const
event
&
x
);
void
handle_console_event
(
event
&
x
);
void
handle_console_event
(
const
event
&
x
);
void
log_first_line
();
void
log_first_line
();
void
log_last_line
();
void
log_last_line
();
logger
(
actor_system
&
sys
);
// -- thread management ------------------------------------------------------
void
init
(
actor_system_config
&
cfg
);
void
run
();
void
run
();
...
@@ -303,78 +338,102 @@ private:
...
@@ -303,78 +338,102 @@ private:
void
stop
();
void
stop
();
inline
bool
has
(
int
flag
)
const
noexcept
{
// -- member variables -------------------------------------------------------
return
(
flags_
&
flag
)
!=
0
;
}
inline
void
set
(
int
flag
)
noexcept
{
// Configures verbosity and output generation.
flags_
|=
flag
;
config
cfg_
;
}
// Filters events by component name.
std
::
string
component_filter
;
// References the parent system.
actor_system
&
system_
;
actor_system
&
system_
;
int
max_level_
;
int
console_level_
;
// Guards aids_.
int
file_level_
;
int
flags_
;
detail
::
shared_spinlock
aids_lock_
;
detail
::
shared_spinlock
aids_lock_
;
// Maps thread IDs to actor IDs.
std
::
unordered_map
<
std
::
thread
::
id
,
actor_id
>
aids_
;
std
::
unordered_map
<
std
::
thread
::
id
,
actor_id
>
aids_
;
std
::
thread
thread_
;
std
::
mutex
queue_mtx_
;
// Identifies the thread that called `logger::start`.
std
::
condition_variable
queue_cv_
;
intrusive
::
fifo_inbox
<
policy
>
queue_
;
std
::
thread
::
id
parent_thread_
;
std
::
thread
::
id
parent_thread_
;
// Timestamp of the first log event.
timestamp
t0_
;
timestamp
t0_
;
// Format for generating file output.
line_format
file_format_
;
line_format
file_format_
;
// Format for generating console output.
line_format
console_format_
;
line_format
console_format_
;
// Stream for file output.
std
::
fstream
file_
;
std
::
fstream
file_
;
std
::
string
component_filter
;
// Filled with log events by other threads.
detail
::
ringbuffer
<
event
,
queue_size
>
queue_
;
// Executes `logger::run`.
std
::
thread
thread_
;
};
};
/// @relates logger::field_type
std
::
string
to_string
(
logger
::
field_type
x
);
std
::
string
to_string
(
logger
::
field_type
x
);
/// @relates logger::field
std
::
string
to_string
(
const
logger
::
field
&
x
);
std
::
string
to_string
(
const
logger
::
field
&
x
);
/// @relates logger::field
bool
operator
==
(
const
logger
::
field
&
x
,
const
logger
::
field
&
y
);
bool
operator
==
(
const
logger
::
field
&
x
,
const
logger
::
field
&
y
);
}
// namespace caf
}
// namespace caf
#define CAF_VOID_STMT static_cast<void>(0)
// -- macro constants ----------------------------------------------------------
#define CAF_CAT(a, b) a##b
#define CAF_LOG_LEVEL_QUIET -1
#define CAF_LOG_LEVEL_ERROR 0
#define CAF_LOG_LEVEL_WARNING 1
#define CAF_LOG_LEVEL_INFO 2
#define CAF_LOG_LEVEL_DEBUG 3
#define CAF_LOG_LEVEL_TRACE 4
#define CAF_ARG(argument) caf::detail::make_arg_wrapper(#argument, argument)
/// Expands to a no-op.
#define CAF_VOID_STMT static_cast<void>(0)
#define CAF_ARG2(argname, argval) caf::detail::make_arg_wrapper(argname, argval)
#ifndef CAF_LOG_COMPONENT
/// Name of the current component when logging.
#define CAF_LOG_COMPONENT "caf"
#endif // CAF_LOG_COMPONENT
#define CAF_ARG3(argname, first, last) \
// -- utility macros -----------------------------------------------------------
caf::detail::make_arg_wrapper(argname, first, last)
#ifdef CAF_MSVC
#ifdef CAF_MSVC
/// Expands to a string representation of the current funciton name that
/// includes the full function name and its signature.
#define CAF_PRETTY_FUN __FUNCSIG__
#define CAF_PRETTY_FUN __FUNCSIG__
#else // CAF_MSVC
#else // CAF_MSVC
/// Expands to a string representation of the current funciton name that
/// includes the full function name and its signature.
#define CAF_PRETTY_FUN __PRETTY_FUNCTION__
#define CAF_PRETTY_FUN __PRETTY_FUNCTION__
#endif // CAF_MSVC
#endif // CAF_MSVC
#ifndef CAF_LOG_COMPONENT
/// Concatenates `a` and `b` to a single preprocessor token.
#define CAF_LOG_COMPONENT "caf"
#define CAF_CAT(a, b) a##b
#endif // CAF_LOG_COMPONENT
#define CAF_LOG_MAKE_EVENT(aid, component, loglvl, message) \
#define CAF_LOG_MAKE_EVENT(aid, component, loglvl, message) \
::caf::logger::event { \
::caf::logger::event { \
loglvl,
component, CAF_PRETTY_FUN, __func__,
\
loglvl,
__LINE__, component, CAF_PRETTY_FUN, __func__,
\
caf::logger::skip_path(__FILE__),
__LINE__,
\
caf::logger::skip_path(__FILE__),
\
(::caf::logger::line_builder{} << message).get(), \
(::caf::logger::line_builder{} << message).get(), \
::std::this_thread::get_id(), aid, ::caf::make_timestamp() \
::std::this_thread::get_id(), aid, ::caf::make_timestamp() \
}
}
#if CAF_LOG_LEVEL == -1
/// Expands to `argument = <argument>` in log output.
#define CAF_ARG(argument) caf::detail::make_arg_wrapper(#argument, argument)
/// Expands to `argname = <argval>` in log output.
#define CAF_ARG2(argname, argval) caf::detail::make_arg_wrapper(argname, argval)
/// Expands to `argname = [argval, last)` in log output.
#define CAF_ARG3(argname, first, last) \
caf::detail::make_arg_wrapper(argname, first, last)
// -- logging macros -----------------------------------------------------------
#if CAF_LOG_LEVEL == CAF_LOG_LEVEL_QUIET
#define CAF_LOG_IMPL(unused1, unused2, unused3)
#define CAF_LOG_IMPL(unused1, unused2, unused3)
...
@@ -391,7 +450,7 @@ inline caf::actor_id caf_set_aid_dummy() { return 0; }
...
@@ -391,7 +450,7 @@ inline caf::actor_id caf_set_aid_dummy() { return 0; }
#define CAF_LOG_TRACE(unused)
#define CAF_LOG_TRACE(unused)
#else // CAF_LOG_LEVEL
#else // CAF_LOG_LEVEL
== CAF_LOG_LEVEL_QUIET
#define CAF_LOG_IMPL(component, loglvl, message) \
#define CAF_LOG_IMPL(component, loglvl, message) \
do { \
do { \
...
@@ -399,8 +458,7 @@ inline caf::actor_id caf_set_aid_dummy() { return 0; }
...
@@ -399,8 +458,7 @@ inline caf::actor_id caf_set_aid_dummy() { return 0; }
if (CAF_UNIFYN(caf_logger) != nullptr \
if (CAF_UNIFYN(caf_logger) != nullptr \
&& CAF_UNIFYN(caf_logger)->accepts(loglvl, component)) \
&& CAF_UNIFYN(caf_logger)->accepts(loglvl, component)) \
CAF_UNIFYN(caf_logger) \
CAF_UNIFYN(caf_logger) \
->log( \
->log(CAF_LOG_MAKE_EVENT(CAF_UNIFYN(caf_logger)->thread_local_aid(), \
new CAF_LOG_MAKE_EVENT(CAF_UNIFYN(caf_logger)->thread_local_aid(), \
component, loglvl, message)); \
component, loglvl, message)); \
} while (false)
} while (false)
...
@@ -458,60 +516,49 @@ inline caf::actor_id caf_set_aid_dummy() { return 0; }
...
@@ -458,60 +516,49 @@ inline caf::actor_id caf_set_aid_dummy() { return 0; }
#define CAF_LOG_ERROR(output) \
#define CAF_LOG_ERROR(output) \
CAF_LOG_IMPL(CAF_LOG_COMPONENT, CAF_LOG_LEVEL_ERROR, output)
CAF_LOG_IMPL(CAF_LOG_COMPONENT, CAF_LOG_LEVEL_ERROR, output)
#endif // CAF_LOG_LEVEL
#endif // CAF_LOG_LEVEL
== CAF_LOG_LEVEL_QUIET
#ifndef CAF_LOG_INFO
#ifndef CAF_LOG_INFO
# define CAF_LOG_INFO(output) CAF_VOID_STMT
#define CAF_LOG_INFO(output) CAF_VOID_STMT
#endif
#define CAF_LOG_INFO_IF(cond, output) CAF_VOID_STMT
#else // CAF_LOG_INFO
#define CAF_LOG_INFO_IF(cond, output) \
if (cond) \
CAF_LOG_IMPL(CAF_LOG_COMPONENT, CAF_LOG_LEVEL_INFO, output); \
CAF_VOID_STMT
#endif // CAF_LOG_INFO
#ifndef CAF_LOG_DEBUG
#ifndef CAF_LOG_DEBUG
# define CAF_LOG_DEBUG(output) CAF_VOID_STMT
#define CAF_LOG_DEBUG(output) CAF_VOID_STMT
#endif
#define CAF_LOG_DEBUG_IF(cond, output) CAF_VOID_STMT
#else // CAF_LOG_DEBUG
#ifndef CAF_LOG_WARNING
# define CAF_LOG_WARNING(output) CAF_VOID_STMT
#endif
#ifndef CAF_LOG_ERROR
# define CAF_LOG_ERROR(output) CAF_VOID_STMT
#endif
#ifdef CAF_LOG_LEVEL
#define CAF_LOG_DEBUG_IF(cond, output) \
#define CAF_LOG_DEBUG_IF(cond, output) \
if (cond)
{
\
if (cond)
\
CAF_LOG_IMPL(CAF_LOG_COMPONENT, CAF_LOG_LEVEL_DEBUG, output); \
CAF_LOG_IMPL(CAF_LOG_COMPONENT, CAF_LOG_LEVEL_DEBUG, output); \
} \
CAF_VOID_STMT
#define CAF_LOG_INFO_IF(cond, output) \
if (cond) { \
CAF_LOG_IMPL(CAF_LOG_COMPONENT, CAF_LOG_LEVEL_INFO, output); \
} \
CAF_VOID_STMT
CAF_VOID_STMT
#endif // CAF_LOG_DEBUG
#ifndef CAF_LOG_WARNING
#define CAF_LOG_WARNING(output) CAF_VOID_STMT
#define CAF_LOG_WARNING_IF(cond, output) CAF_VOID_STMT
#else // CAF_LOG_WARNING
#define CAF_LOG_WARNING_IF(cond, output) \
#define CAF_LOG_WARNING_IF(cond, output) \
if (cond)
{
\
if (cond)
\
CAF_LOG_IMPL(CAF_LOG_COMPONENT, CAF_LOG_LEVEL_WARNING, output); \
CAF_LOG_IMPL(CAF_LOG_COMPONENT, CAF_LOG_LEVEL_WARNING, output); \
} \
CAF_VOID_STMT
CAF_VOID_STMT
#endif // CAF_LOG_WARNING
#ifndef CAF_LOG_ERROR
#define CAF_LOG_ERROR(output) CAF_VOID_STMT
#define CAF_LOG_ERROR_IF(cond, output) CAF_VOID_STMT
#else // CAF_LOG_ERROR
#define CAF_LOG_ERROR_IF(cond, output) \
#define CAF_LOG_ERROR_IF(cond, output) \
if (cond)
{
\
if (cond)
\
CAF_LOG_IMPL(CAF_LOG_COMPONENT, CAF_LOG_LEVEL_ERROR, output); \
CAF_LOG_IMPL(CAF_LOG_COMPONENT, CAF_LOG_LEVEL_ERROR, output); \
} \
CAF_VOID_STMT
CAF_VOID_STMT
#endif // CAF_LOG_ERROR
#else // CAF_LOG_LEVEL
// -- macros for logging CE-0001 events ----------------------------------------
#define CAF_LOG_DEBUG_IF(unused1, unused2)
#define CAF_LOG_INFO_IF(unused1, unused2)
#define CAF_LOG_WARNING_IF(unused1, unused2)
#define CAF_LOG_ERROR_IF(unused1, unused2)
#endif // CAF_LOG_LEVEL
// -- Standardized CAF events according to SE-0001.
/// The log component responsible for logging control flow events that are
/// The log component responsible for logging control flow events that are
/// crucial for understanding happens-before relations. See RFC SE-0001.
/// crucial for understanding happens-before relations. See RFC SE-0001.
...
...
libcaf_core/src/atom.cpp
View file @
168a2a2b
...
@@ -18,34 +18,57 @@
...
@@ -18,34 +18,57 @@
#include "caf/atom.hpp"
#include "caf/atom.hpp"
#include <array>
#include <cstring>
#include <cstring>
#include "caf/string_view.hpp"
namespace
caf
{
namespace
caf
{
atom_value
atom_from_string
(
const
std
::
string
&
x
)
{
namespace
{
if
(
x
.
size
()
>
10
)
return
atom
(
""
);
/// A buffer for decoding atom values.
char
buf
[
11
];
using
atom_value_buf
=
std
::
array
<
char
,
11
>
;
memcpy
(
buf
,
x
.
c_str
(),
x
.
size
());
buf
[
x
.
size
()]
=
'\0'
;
return
atom
(
buf
);
}
std
::
string
to_string
(
const
atom_value
&
what
)
{
size_t
decode
(
atom_value_buf
&
buf
,
atom_value
what
)
{
size_t
pos
=
0
;
auto
x
=
static_cast
<
uint64_t
>
(
what
);
auto
x
=
static_cast
<
uint64_t
>
(
what
);
std
::
string
result
;
// Don't read characters before we found the leading 0xF.
result
.
reserve
(
11
);
// don't read characters before we found the leading 0xF
// first four bits set?
bool
read_chars
=
((
x
&
0xF000000000000000
)
>>
60
)
==
0xF
;
bool
read_chars
=
((
x
&
0xF000000000000000
)
>>
60
)
==
0xF
;
uint64_t
mask
=
0x0FC0000000000000
;
uint64_t
mask
=
0x0FC0000000000000
;
for
(
int
bitshift
=
54
;
bitshift
>=
0
;
bitshift
-=
6
,
mask
>>=
6
)
{
for
(
int
bitshift
=
54
;
bitshift
>=
0
;
bitshift
-=
6
,
mask
>>=
6
)
{
if
(
read_chars
)
if
(
read_chars
)
result
+
=
detail
::
decoding_table
[(
x
&
mask
)
>>
bitshift
];
buf
[
pos
++
]
=
detail
::
decoding_table
[(
x
&
mask
)
>>
bitshift
];
else
if
(((
x
&
mask
)
>>
bitshift
)
==
0xF
)
else
if
(((
x
&
mask
)
>>
bitshift
)
==
0xF
)
read_chars
=
true
;
read_chars
=
true
;
}
}
return
result
;
buf
[
pos
]
=
'\0'
;
return
pos
;
}
}
// namespace <anonymous>
atom_value
to_lowercase
(
atom_value
x
)
{
atom_value_buf
buf
;
decode
(
buf
,
x
);
for
(
auto
ch
=
buf
.
data
();
*
ch
!=
'\0'
;
++
ch
)
*
ch
=
static_cast
<
char
>
(
tolower
(
*
ch
));
return
static_cast
<
atom_value
>
(
detail
::
atom_val
(
buf
.
data
()));
}
atom_value
atom_from_string
(
const
std
::
string
&
x
)
{
if
(
x
.
size
()
>
10
)
return
atom
(
""
);
atom_value_buf
buf
;
memcpy
(
buf
.
data
(),
x
.
c_str
(),
x
.
size
());
buf
[
x
.
size
()]
=
'\0'
;
return
static_cast
<
atom_value
>
(
detail
::
atom_val
(
buf
.
data
()));
}
std
::
string
to_string
(
const
atom_value
&
x
)
{
atom_value_buf
str
;
auto
len
=
decode
(
str
,
x
);
return
std
::
string
(
str
.
begin
(),
str
.
begin
()
+
len
);
}
}
}
// namespace caf
}
// namespace caf
libcaf_core/src/logger.cpp
View file @
168a2a2b
...
@@ -48,11 +48,22 @@ namespace caf {
...
@@ -48,11 +48,22 @@ namespace caf {
namespace
{
namespace
{
constexpr
string_view
log_level_name
[]
=
{
constexpr
string_view
log_level_name
[]
=
{
"QUIET"
,
""
,
""
,
"ERROR"
,
"ERROR"
,
""
,
""
,
"WARN"
,
"WARN"
,
""
,
""
,
"INFO"
,
"INFO"
,
""
,
""
,
"DEBUG"
,
"DEBUG"
,
"TRACE"
""
,
""
,
"TRACE"
,
};
};
constexpr
string_view
fun_prefixes
[]
=
{
constexpr
string_view
fun_prefixes
[]
=
{
...
@@ -70,6 +81,26 @@ constexpr string_view anon_ns[] = {
...
@@ -70,6 +81,26 @@ constexpr string_view anon_ns[] = {
"`anonymous-namespace'"
,
// MSVC
"`anonymous-namespace'"
,
// MSVC
};
};
/// Converts a verbosity atom to its integer counterpart.
unsigned
to_level_int
(
atom_value
x
)
{
switch
(
atom_uint
(
to_lowercase
(
x
)))
{
default:
return
CAF_LOG_LEVEL_QUIET
;
case
atom_uint
(
"quiet"
):
return
CAF_LOG_LEVEL_QUIET
;
case
atom_uint
(
"error"
):
return
CAF_LOG_LEVEL_ERROR
;
case
atom_uint
(
"warning"
):
return
CAF_LOG_LEVEL_WARNING
;
case
atom_uint
(
"info"
):
return
CAF_LOG_LEVEL_INFO
;
case
atom_uint
(
"debug"
):
return
CAF_LOG_LEVEL_DEBUG
;
case
atom_uint
(
"trace"
):
return
CAF_LOG_LEVEL_TRACE
;
}
}
// Reduces symbol by printing all prefixes to `out` and returning the
// Reduces symbol by printing all prefixes to `out` and returning the
// remainder. For example, "ns::foo::bar" prints "ns.foo" to `out` and returns
// remainder. For example, "ns::foo::bar" prints "ns.foo" to `out` and returns
// "bar".
// "bar".
...
@@ -214,15 +245,25 @@ inline logger* get_current_logger() {
...
@@ -214,15 +245,25 @@ inline logger* get_current_logger() {
}
// namespace <anonymous>
}
// namespace <anonymous>
logger
::
event
::
event
(
int
lvl
,
string_view
cat
,
string_view
full_fun
,
logger
::
config
::
config
()
string_view
fun
,
string_view
fn
,
int
line
,
std
::
string
msg
,
:
verbosity
(
CAF_LOG_LEVEL
),
std
::
thread
::
id
t
,
actor_id
a
,
timestamp
ts
)
file_verbosity
(
CAF_LOG_LEVEL
),
console_verbosity
(
CAF_LOG_LEVEL
),
inline_output
(
false
),
console_coloring
(
false
)
{
// nop
}
logger
::
event
::
event
(
unsigned
lvl
,
unsigned
line
,
string_view
cat
,
string_view
full_fun
,
string_view
fun
,
string_view
fn
,
std
::
string
msg
,
std
::
thread
::
id
t
,
actor_id
a
,
timestamp
ts
)
:
level
(
lvl
),
:
level
(
lvl
),
line_number
(
line
),
category_name
(
cat
),
category_name
(
cat
),
pretty_fun
(
full_fun
),
pretty_fun
(
full_fun
),
simple_fun
(
fun
),
simple_fun
(
fun
),
file_name
(
fn
),
file_name
(
fn
),
line_number
(
line
),
message
(
std
::
move
(
msg
)),
message
(
std
::
move
(
msg
)),
tid
(
std
::
move
(
t
)),
tid
(
std
::
move
(
t
)),
aid
(
a
),
aid
(
a
),
...
@@ -292,14 +333,11 @@ actor_id logger::thread_local_aid(actor_id aid) {
...
@@ -292,14 +333,11 @@ actor_id logger::thread_local_aid(actor_id aid) {
return
0
;
// was empty before
return
0
;
// was empty before
}
}
void
logger
::
log
(
event
*
x
)
{
void
logger
::
log
(
event
&&
x
)
{
CAF_ASSERT
(
x
->
level
>=
0
&&
x
->
level
<=
4
);
if
(
cfg_
.
inline_output
)
if
(
has
(
inline_output_flag
))
{
handle_event
(
x
);
std
::
unique_ptr
<
event
>
ptr
{
x
};
else
handle_event
(
*
ptr
);
queue_
.
push_back
(
std
::
move
(
x
));
}
else
{
queue_
.
synchronized_push_back
(
queue_mtx_
,
queue_cv_
,
x
);
}
}
}
void
logger
::
set_current_actor_system
(
actor_system
*
x
)
{
void
logger
::
set_current_actor_system
(
actor_system
*
x
)
{
...
@@ -313,9 +351,8 @@ logger* logger::current_logger() {
...
@@ -313,9 +351,8 @@ logger* logger::current_logger() {
return
get_current_logger
();
return
get_current_logger
();
}
}
bool
logger
::
accepts
(
int
level
,
string_view
cname
)
{
bool
logger
::
accepts
(
unsigned
level
,
string_view
cname
)
{
CAF_ASSERT
(
level
>=
0
&&
level
<=
4
);
if
(
level
>
cfg_
.
verbosity
)
if
(
level
>
max_level_
)
return
false
;
return
false
;
if
(
!
component_filter
.
empty
())
{
if
(
!
component_filter
.
empty
())
{
auto
it
=
std
::
search
(
component_filter
.
begin
(),
component_filter
.
end
(),
auto
it
=
std
::
search
(
component_filter
.
begin
(),
component_filter
.
end
(),
...
@@ -325,6 +362,10 @@ bool logger::accepts(int level, string_view cname) {
...
@@ -325,6 +362,10 @@ bool logger::accepts(int level, string_view cname) {
return
true
;
return
true
;
}
}
logger
::
logger
(
actor_system
&
sys
)
:
system_
(
sys
)
{
// nop
}
logger
::~
logger
()
{
logger
::~
logger
()
{
stop
();
stop
();
// tell system our dtor is done
// tell system our dtor is done
...
@@ -333,46 +374,8 @@ logger::~logger() {
...
@@ -333,46 +374,8 @@ logger::~logger() {
system_
.
logger_dtor_cv_
.
notify_one
();
system_
.
logger_dtor_cv_
.
notify_one
();
}
}
logger
::
logger
(
actor_system
&
sys
)
:
system_
(
sys
),
max_level_
(
CAF_LOG_LEVEL
),
flags_
(
0
),
queue_
(
policy
{})
{
// nop
}
namespace
{
int
to_level_int
(
const
atom_value
atom
)
{
switch
(
atom_uint
(
atom
))
{
case
atom_uint
(
"quiet"
):
case
atom_uint
(
"QUIET"
):
return
CAF_LOG_LEVEL_QUIET
;
case
atom_uint
(
"error"
):
case
atom_uint
(
"ERROR"
):
return
CAF_LOG_LEVEL_ERROR
;
case
atom_uint
(
"warning"
):
case
atom_uint
(
"WARNING"
):
return
CAF_LOG_LEVEL_WARNING
;
case
atom_uint
(
"info"
):
case
atom_uint
(
"INFO"
):
return
CAF_LOG_LEVEL_INFO
;
case
atom_uint
(
"debug"
):
case
atom_uint
(
"DEBUG"
):
return
CAF_LOG_LEVEL_DEBUG
;
case
atom_uint
(
"trace"
):
case
atom_uint
(
"TRACE"
):
return
CAF_LOG_LEVEL_TRACE
;
default:
{
// nop
}
}
return
CAF_LOG_LEVEL_QUIET
;
}
}
// namespace
void
logger
::
init
(
actor_system_config
&
cfg
)
{
void
logger
::
init
(
actor_system_config
&
cfg
)
{
CAF_IGNORE_UNUSED
(
cfg
);
CAF_IGNORE_UNUSED
(
cfg
);
#if CAF_LOG_LEVEL >= 0
namespace
lg
=
defaults
::
logger
;
namespace
lg
=
defaults
::
logger
;
component_filter
=
get_or
(
cfg
,
"logger.component-filter"
,
component_filter
=
get_or
(
cfg
,
"logger.component-filter"
,
lg
::
component_filter
);
lg
::
component_filter
);
...
@@ -383,9 +386,9 @@ void logger::init(actor_system_config& cfg) {
...
@@ -383,9 +386,9 @@ void logger::init(actor_system_config& cfg) {
file_verbosity
=
get_or
(
cfg
,
"logger.file-verbosity"
,
file_verbosity
);
file_verbosity
=
get_or
(
cfg
,
"logger.file-verbosity"
,
file_verbosity
);
console_verbosity
=
console_verbosity
=
get_or
(
cfg
,
"logger.console-verbosity"
,
console_verbosity
);
get_or
(
cfg
,
"logger.console-verbosity"
,
console_verbosity
);
file_level_
=
to_level_int
(
file_verbosity
);
cfg_
.
file_verbosity
=
to_level_int
(
file_verbosity
);
c
onsole_level_
=
to_level_int
(
console_verbosity
);
c
fg_
.
console_verbosity
=
to_level_int
(
console_verbosity
);
max_level_
=
std
::
max
(
file_level_
,
console_level_
);
cfg_
.
verbosity
=
std
::
max
(
cfg_
.
file_verbosity
,
cfg_
.
console_verbosity
);
// Parse the format string.
// Parse the format string.
file_format_
=
file_format_
=
parse_format
(
get_or
(
cfg
,
"logger.file-format"
,
lg
::
file_format
));
parse_format
(
get_or
(
cfg
,
"logger.file-format"
,
lg
::
file_format
));
...
@@ -393,13 +396,14 @@ void logger::init(actor_system_config& cfg) {
...
@@ -393,13 +396,14 @@ void logger::init(actor_system_config& cfg) {
lg
::
console_format
));
lg
::
console_format
));
// Set flags.
// Set flags.
if
(
get_or
(
cfg
,
"logger.inline-output"
,
false
))
if
(
get_or
(
cfg
,
"logger.inline-output"
,
false
))
set
(
inline_output_flag
)
;
cfg_
.
inline_output
=
true
;
auto
con_atm
=
get_or
(
cfg
,
"logger.console"
,
lg
::
console
);
auto
con_atm
=
get_or
(
cfg
,
"logger.console"
,
lg
::
console
);
if
(
con_atm
==
atom
(
"UNCOLORED"
))
if
(
to_lowercase
(
con_atm
)
==
atom
(
"colored"
))
{
set
(
uncolored_console_flag
);
cfg_
.
console_coloring
=
true
;
else
if
(
con_atm
==
atom
(
"COLORED"
))
}
else
if
(
to_lowercase
(
con_atm
)
!=
atom
(
"uncolored"
))
{
set
(
colored_console_flag
);
// Disable console output if neither 'colored' nor 'uncolored' are present.
#endif
cfg_
.
console_verbosity
=
CAF_LOG_LEVEL_QUIET
;
}
}
}
void
logger
::
render_fun_prefix
(
std
::
ostream
&
out
,
const
event
&
x
)
{
void
logger
::
render_fun_prefix
(
std
::
ostream
&
out
,
const
event
&
x
)
{
...
@@ -543,42 +547,29 @@ string_view logger::skip_path(string_view path) {
...
@@ -543,42 +547,29 @@ string_view logger::skip_path(string_view path) {
}
}
void
logger
::
run
()
{
void
logger
::
run
()
{
#if CAF_LOG_LEVEL >= 0
log_first_line
();
log_first_line
();
// receive log entries from other threads and actors
for
(;;)
{
bool
stop
=
false
;
queue_
.
wait_nonempty
();
auto
f
=
[
&
](
event
&
x
)
{
auto
&
e
=
queue_
.
front
();
// empty message means: shut down
if
(
e
.
message
.
empty
())
{
if
(
x
.
message
.
empty
())
{
stop
=
true
;
return
intrusive
::
task_result
::
stop
;
}
handle_event
(
x
);
return
intrusive
::
task_result
::
resume
;
};
do
{
// make sure we have data to read and consume events
queue_
.
synchronized_await
(
queue_mtx_
,
queue_cv_
);
queue_
.
new_round
(
1000
,
f
);
}
while
(
!
stop
);
log_last_line
();
log_last_line
();
#endif
return
;
}
handle_event
(
e
);
queue_
.
pop_front
();
}
}
}
void
logger
::
handle_file_event
(
event
&
x
)
{
void
logger
::
handle_file_event
(
const
event
&
x
)
{
// Print to file if available.
// Print to file if available.
if
(
file_
&&
x
.
level
<=
file_
level_
)
if
(
file_
&&
x
.
level
<=
file_
verbosity
()
)
render
(
file_
,
file_format_
,
x
);
render
(
file_
,
file_format_
,
x
);
}
}
void
logger
::
handle_console_event
(
event
&
x
)
{
void
logger
::
handle_console_event
(
const
event
&
x
)
{
// Stop if no console output is configured.
if
(
x
.
level
>
console_verbosity
())
if
(
!
has
(
console_output_flag
)
||
x
.
level
>
console_level_
)
return
;
return
;
if
(
has
(
uncolored_console_flag
))
{
if
(
cfg_
.
console_coloring
)
{
render
(
std
::
clog
,
console_format_
,
x
);
std
::
clog
<<
std
::
endl
;
}
else
{
switch
(
x
.
level
)
{
switch
(
x
.
level
)
{
default:
default:
break
;
break
;
...
@@ -600,63 +591,50 @@ void logger::handle_console_event(event& x) {
...
@@ -600,63 +591,50 @@ void logger::handle_console_event(event& x) {
}
}
render
(
std
::
clog
,
console_format_
,
x
);
render
(
std
::
clog
,
console_format_
,
x
);
std
::
clog
<<
term
::
reset_endl
;
std
::
clog
<<
term
::
reset_endl
;
}
else
{
render
(
std
::
clog
,
console_format_
,
x
);
std
::
clog
<<
std
::
endl
;
}
}
}
}
void
logger
::
handle_event
(
event
&
x
)
{
void
logger
::
handle_event
(
const
event
&
x
)
{
handle_file_event
(
x
);
handle_file_event
(
x
);
handle_console_event
(
x
);
handle_console_event
(
x
);
}
}
void
logger
::
log_first_line
()
{
void
logger
::
log_first_line
()
{
auto
make_event
=
[
&
](
string_view
config_val
,
auto
e
=
CAF_LOG_MAKE_EVENT
(
0
,
CAF_LOG_COMPONENT
,
CAF_LOG_LEVEL_DEBUG
,
""
);
const
atom_value
default_val
)
->
event
{
auto
make_message
=
[
&
](
string_view
config_name
,
atom_value
default_value
)
{
std
::
string
msg
=
"level = "
;
std
::
string
msg
=
"level = "
;
msg
+=
to_string
(
get_or
(
system_
.
config
(),
config_
val
,
default_val
));
msg
+=
to_string
(
get_or
(
system_
.
config
(),
config_
name
,
default_value
));
msg
+=
", node = "
;
msg
+=
", node = "
;
msg
+=
to_string
(
system_
.
node
());
msg
+=
to_string
(
system_
.
node
());
return
{
CAF_LOG_LEVEL_INFO
,
msg
+=
", component_filter = "
;
CAF_LOG_COMPONENT
,
msg
+=
deep_to_string
(
component_filter
);
CAF_PRETTY_FUN
,
return
msg
;
__func__
,
__FILE__
,
__LINE__
,
std
::
move
(
msg
),
std
::
this_thread
::
get_id
(),
0
,
make_timestamp
()};
};
};
event
file
=
make_event
(
"logger.file-verbosity"
,
defaults
::
logger
::
file_verbosity
);
namespace
lg
=
defaults
::
logger
;
handle_file_event
(
file
);
e
.
message
=
make_message
(
"logger.file-verbosity"
,
lg
::
file_verbosity
);
event
console
=
make_event
(
"logger.console-verbosity"
,
defaults
::
logger
::
console_verbosity
);
handle_file_event
(
e
);
handle_console_event
(
console
);
e
.
message
=
make_message
(
"logger.console-verbosity"
,
lg
::
console_verbosity
);
handle_console_event
(
e
);
}
}
void
logger
::
log_last_line
()
{
void
logger
::
log_last_line
()
{
event
tmp
{
CAF_LOG_LEVEL_INFO
,
auto
e
=
CAF_LOG_MAKE_EVENT
(
0
,
CAF_LOG_COMPONENT
,
CAF_LOG_LEVEL_DEBUG
,
""
);
CAF_LOG_COMPONENT
,
handle_event
(
e
);
CAF_PRETTY_FUN
,
__func__
,
__FILE__
,
__LINE__
,
"EOF"
,
std
::
this_thread
::
get_id
(),
0
,
make_timestamp
()};
handle_event
(
tmp
);
}
}
void
logger
::
start
()
{
void
logger
::
start
()
{
#if CAF_LOG_LEVEL >= 0
parent_thread_
=
std
::
this_thread
::
get_id
();
parent_thread_
=
std
::
this_thread
::
get_id
();
if
(
max_level_
==
CAF_LOG_LEVEL_QUIET
)
if
(
verbosity
()
==
CAF_LOG_LEVEL_QUIET
)
return
;
return
;
t0_
=
make_timestamp
();
t0_
=
make_timestamp
();
auto
f
=
get_or
(
system_
.
config
(),
"logger.file-name"
,
auto
f
=
get_or
(
system_
.
config
(),
"logger.file-name"
,
defaults
::
logger
::
file_name
);
defaults
::
logger
::
file_name
);
if
(
f
.
empty
())
{
if
(
f
.
empty
())
{
// No need to continue if console and log file are disabled.
// No need to continue if console and log file are disabled.
if
(
has
(
console_output_flag
)
)
if
(
console_verbosity
()
==
CAF_LOG_LEVEL_QUIET
)
return
;
return
;
}
else
{
}
else
{
// Replace placeholders.
// Replace placeholders.
...
@@ -685,7 +663,7 @@ void logger::start() {
...
@@ -685,7 +663,7 @@ void logger::start() {
return
;
return
;
}
}
}
}
if
(
has
(
inline_output_flag
)
)
if
(
cfg_
.
inline_output
)
log_first_line
();
log_first_line
();
else
else
thread_
=
std
::
thread
{[
this
]
{
thread_
=
std
::
thread
{[
this
]
{
...
@@ -694,21 +672,18 @@ void logger::start() {
...
@@ -694,21 +672,18 @@ void logger::start() {
this
->
run
();
this
->
run
();
this
->
system_
.
thread_terminates
();
this
->
system_
.
thread_terminates
();
}};
}};
#endif
}
}
void
logger
::
stop
()
{
void
logger
::
stop
()
{
#if CAF_LOG_LEVEL >= 0
if
(
cfg_
.
inline_output
)
{
if
(
has
(
inline_output_flag
))
{
log_last_line
();
log_last_line
();
return
;
return
;
}
}
if
(
!
thread_
.
joinable
())
if
(
!
thread_
.
joinable
())
return
;
return
;
//
an empty string means: shut down
//
A default-constructed event causes the logger to shutdown.
queue_
.
synchronized_push_back
(
queue_mtx_
,
queue_cv_
,
new
event
);
queue_
.
push_back
(
event
{}
);
thread_
.
join
();
thread_
.
join
();
#endif
}
}
std
::
string
to_string
(
logger
::
field_type
x
)
{
std
::
string
to_string
(
logger
::
field_type
x
)
{
...
...
libcaf_core/test/logger.cpp
View file @
168a2a2b
...
@@ -179,11 +179,11 @@ CAF_TEST(rendering) {
...
@@ -179,11 +179,11 @@ CAF_TEST(rendering) {
// Rendering of events.
// Rendering of events.
logger
::
event
e
{
logger
::
event
e
{
CAF_LOG_LEVEL_WARNING
,
CAF_LOG_LEVEL_WARNING
,
42
,
"unit.test"
,
"unit.test"
,
"void ns::foo::bar()"
,
"void ns::foo::bar()"
,
"bar"
,
"bar"
,
"foo.cpp"
,
"foo.cpp"
,
42
,
"hello world"
,
"hello world"
,
std
::
this_thread
::
get_id
(),
std
::
this_thread
::
get_id
(),
0
,
0
,
...
...
libcaf_core/test/ringbuffer.cpp
0 → 100644
View file @
168a2a2b
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE ringbuffer
#include "caf/detail/ringbuffer.hpp"
#include "caf/test/dsl.hpp"
#include <algorithm>
using
namespace
caf
;
namespace
{
static
constexpr
size_t
buf_size
=
64
;
using
int_ringbuffer
=
detail
::
ringbuffer
<
int
,
buf_size
>
;
std
::
vector
<
int
>
consumer
(
int_ringbuffer
&
buf
,
size_t
num
)
{
std
::
vector
<
int
>
result
;
for
(
size_t
i
=
0
;
i
<
num
;
++
i
)
{
buf
.
wait_nonempty
();
result
.
emplace_back
(
buf
.
front
());
buf
.
pop_front
();
}
return
result
;
}
void
producer
(
int_ringbuffer
&
buf
,
int
first
,
int
last
)
{
for
(
auto
i
=
first
;
i
!=
last
;
++
i
)
buf
.
push_back
(
std
::
move
(
i
));
}
struct
fixture
{
int_ringbuffer
buf
;
};
}
// namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE
(
ringbuffer_tests
,
fixture
)
CAF_TEST
(
construction
)
{
CAF_CHECK_EQUAL
(
buf
.
empty
(),
true
);
CAF_CHECK_EQUAL
(
buf
.
full
(),
false
);
CAF_CHECK_EQUAL
(
buf
.
size
(),
0u
);
}
CAF_TEST
(
push_back
)
{
CAF_MESSAGE
(
"add one element"
);
buf
.
push_back
(
42
);
CAF_CHECK_EQUAL
(
buf
.
empty
(),
false
);
CAF_CHECK_EQUAL
(
buf
.
full
(),
false
);
CAF_CHECK_EQUAL
(
buf
.
size
(),
1u
);
CAF_CHECK_EQUAL
(
buf
.
front
(),
42
);
CAF_MESSAGE
(
"remove element"
);
buf
.
pop_front
();
CAF_CHECK_EQUAL
(
buf
.
empty
(),
true
);
CAF_CHECK_EQUAL
(
buf
.
full
(),
false
);
CAF_CHECK_EQUAL
(
buf
.
size
(),
0u
);
CAF_MESSAGE
(
"fill buffer"
);
for
(
int
i
=
0
;
i
<
static_cast
<
int
>
(
buf_size
-
1
);
++
i
)
buf
.
push_back
(
std
::
move
(
i
));
CAF_CHECK_EQUAL
(
buf
.
empty
(),
false
);
CAF_CHECK_EQUAL
(
buf
.
full
(),
true
);
CAF_CHECK_EQUAL
(
buf
.
size
(),
buf_size
-
1
);
CAF_CHECK_EQUAL
(
buf
.
front
(),
0
);
}
CAF_TEST
(
concurrent
access
)
{
std
::
vector
<
std
::
thread
>
producers
;
producers
.
emplace_back
(
producer
,
std
::
ref
(
buf
),
0
,
100
);
producers
.
emplace_back
(
producer
,
std
::
ref
(
buf
),
100
,
200
);
producers
.
emplace_back
(
producer
,
std
::
ref
(
buf
),
200
,
300
);
auto
vec
=
consumer
(
buf
,
300
);
std
::
sort
(
vec
.
begin
(),
vec
.
end
());
CAF_CHECK
(
std
::
is_sorted
(
vec
.
begin
(),
vec
.
end
()));
CAF_CHECK_EQUAL
(
vec
.
size
(),
300u
);
CAF_CHECK_EQUAL
(
vec
.
front
(),
0
);
CAF_CHECK_EQUAL
(
vec
.
back
(),
299
);
for
(
auto
&
t
:
producers
)
t
.
join
();
}
CAF_TEST_FIXTURE_SCOPE_END
()
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