Skip to content

Commit 96a49df

Browse files
authored
Refactor Log Event Handler (#14)
* Add implementation Signed-off-by: jparisu <javierparis@eprosima.com> * Add tests Signed-off-by: jparisu <javierparis@eprosima.com> * Fix ASAN issue Signed-off-by: jparisu <javierparis@eprosima.com> * Add documentation Signed-off-by: jparisu <javierparis@eprosima.com> * Fix windows compilation Signed-off-by: jparisu <javierparis@eprosima.com> * Add LogChecker documentation Signed-off-by: jparisu <javierparis@eprosima.com> * fix bug in new implementation Signed-off-by: jparisu <javierparis@eprosima.com> * uncrustify Signed-off-by: jparisu <javierparis@eprosima.com> Signed-off-by: jparisu <javierparis@eprosima.com>
1 parent c37323c commit 96a49df

12 files changed

Lines changed: 601 additions & 77 deletions

File tree

cpp_utils/include/cpp_utils/event/LogEventHandler.hpp

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,45 @@
2222
#include <functional>
2323

2424
#include <cpp_utils/Log.hpp>
25+
#include <cpp_utils/types/Atomicable.hpp>
2526
#include <cpp_utils/event/EventHandler.hpp>
27+
#include <cpp_utils/memory/owner_ptr.hpp>
2628
#include <cpp_utils/library/library_dll.h>
2729

2830
namespace eprosima {
2931
namespace utils {
3032
namespace event {
3133

34+
//! Data Type to be shared between a LogEventHandler and a LogConsumerConnection.
35+
using LogConsumerConnectionCallbackType = std::function<void (const utils::Log::Entry&)>;
36+
3237
/**
3338
* It implements the functionality to raise callback every time a Log msg is consumed.
3439
*
35-
* @warning Fast DDS Log takes the ownership of the pointer of every new consumer (because of reasons...)
36-
* Thus, in order to create this kind of handler, it must be created from a pointer (new) and the ownership
37-
* of the pointer will be lost as soon as it is created.
40+
* As Fast DDS Log requires to own a unique_ptr with a consumer, this class is separated from \c LogConsumer.
41+
* The actual \c LogConsumer used is of class \c LogConsumerConnection and every time it consumes an \c Entry ,
42+
* it calls this class.
43+
* As \c LogConsumerConnection variable will survive this object, an owner/lessee object is shared between
44+
* both objects, so connection keeps calling this callback as long as this object lives, and after this death
45+
* it will do nothing.
3846
*/
39-
class LogEventHandler : public EventHandler<utils::Log::Entry>, utils::LogConsumer
47+
class LogEventHandler : public EventHandler<utils::Log::Entry>
4048
{
4149
public:
4250

43-
// This class does not have constructor without callback.
44-
// This is because of the lost of the pointer once it is registered in Fast. This makes it simpler.
51+
/**
52+
* Construct without callback.
53+
*
54+
* It registers in Log the LogConsumer that will call this object.
55+
*/
56+
CPP_UTILS_DllAPI LogEventHandler();
4557

4658
/**
4759
* Construct a Log Event Handler with callback and enable it.
4860
*
49-
* Calls \c set_callback
61+
* It registers in Log the LogConsumer that will call this object.
62+
*
63+
* Calls \c set_callback .
5064
*
5165
* @param callback callback to call every time a log entry is consumed.
5266
*/
@@ -60,34 +74,32 @@ class LogEventHandler : public EventHandler<utils::Log::Entry>, utils::LogConsum
6074
*/
6175
CPP_UTILS_DllAPI ~LogEventHandler();
6276

63-
CPP_UTILS_DllAPI void Consume(
64-
const utils::Log::Entry& entry) override;
65-
6677
protected:
6778

6879
/**
69-
* @brief Override \c callback_set_nts_ from \c EventHandler .
80+
* @brief Consumes an \c Entry given from the \c LogConsumerConnection .
7081
*
71-
* The first time is called, it registers the consumer into Log.
82+
* @param entry entry consumed.
7283
*/
73-
virtual void callback_set_nts_() noexcept override;
74-
75-
//! Whether the object has been registered in the Log (as soon as it is created in this class)
76-
std::atomic<bool> first_registered_;
84+
CPP_UTILS_DllAPI virtual void consume_(
85+
const utils::Log::Entry& entry);
7786

7887
/**
79-
* @brief Vector of Log entries consumed so far.
88+
* @brief Shared object between this and \c LogConsumerConnection registered.
8089
*
81-
* Guarded by \c entries_mutex_ .
90+
* When this is destroyed, the ptr is released and the lessee in \c LogConsumerConnection will no longer
91+
* be valid, so that object will do nothing with any new Entry.
8292
*/
83-
std::vector<utils::Log::Entry> entries_consumed_;
93+
OwnerPtr<LogConsumerConnectionCallbackType> connection_callback_;
8494

85-
//! Guard access to \c entries_consumed_
86-
mutable std::mutex entries_mutex_;
95+
/**
96+
* @brief Vector of Log entries consumed so far.
97+
*
98+
* Guarded by itself.
99+
*/
100+
SharedAtomicable<std::vector<utils::Log::Entry>> entries_consumed_;
87101
};
88102

89103
} /* namespace event */
90104
} /* namespace utils */
91105
} /* namespace eprosima */
92-
93-

cpp_utils/include/cpp_utils/event/LogSevereEventHandler.hpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,16 @@ class LogSevereEventHandler : public LogEventHandler
4848
std::function<void(utils::Log::Entry)> callback,
4949
const utils::Log::Kind threshold = utils::Log::Kind::Warning);
5050

51-
//! Override parent \c Consume method but only consuming logs above the \c threshold_ kind.
52-
CPP_UTILS_DllAPI void Consume(
53-
const utils::Log::Entry& entry) override;
54-
5551
protected:
5652

53+
//! Override parent \c consume_ method but only consuming logs above the \c threshold_ kind.
54+
CPP_UTILS_DllAPI void consume_(
55+
const utils::Log::Entry& entry) override;
56+
5757
//! Minimum Log kind accepted to consumed.
5858
utils::Log::Kind threshold_;
5959
};
6060

6161
} /* namespace event */
6262
} /* namespace utils */
6363
} /* namespace eprosima */
64-
65-

cpp_utils/include/cpp_utils/testing/LogChecker.hpp

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,32 +25,62 @@
2525

2626
namespace eprosima {
2727
namespace utils {
28-
namespace test {
28+
namespace testing {
2929

30+
/**
31+
* @brief This is an auxiliary class to check the logs produced in a test.
32+
*
33+
* The main idea is to create one of this objects at the beginning of a test execution, and it will
34+
* have a counter of the logs consumed (only those higher than threshold given).
35+
* At the end, \c check_valid() should be called in order to know if the logs consumed are between the minimum
36+
* and maximum logs expected.
37+
*
38+
* In order to automatically check that no warnings nor errors are produced by a test,
39+
* call \c DEFAULT_LOG_TESTER macro at the beginning of the test.
40+
* To use specific arguments, use \c INSTANTIATE_LOG_TESTER instead.
41+
*/
3042
class LogChecker
3143
{
3244
public:
3345

46+
/**
47+
* @brief Construct a LogChecker object.
48+
*
49+
* @param threshold minimum log level that will be taken into account when counting logs consumed.
50+
* @param expected_severe_logs the number of logs this object expects to consumed.
51+
* @param max_severe_logs the maximum number of logs this object will allow.
52+
*/
3453
CPP_UTILS_DllAPI LogChecker(
3554
utils::Log::Kind threshold = utils::Log::Kind::Warning,
36-
uint32_t expected_severe_logs = 0,
37-
uint32_t max_severe_logs = 0);
55+
unsigned int expected_severe_logs = 0,
56+
unsigned int max_severe_logs = 0);
3857

39-
CPP_UTILS_DllAPI ~LogChecker();
58+
//! Default destructor.
59+
CPP_UTILS_DllAPI ~LogChecker() = default;
4060

61+
/**
62+
* @brief Whether the logs consumed so far are between the limits expected.
63+
*
64+
* @return true if logs consumed are equal ot higher than \c expected_severe_logs
65+
* and equal or lower than \c max_severe_logs .
66+
* false otherwise.
67+
*/
4168
CPP_UTILS_DllAPI bool check_valid();
4269

4370
protected:
4471

4572
/**
46-
* @brief Pointer to the event handler log consumer
73+
* @brief Log Handler object.
4774
*
48-
* @attention: this must be a raw pointer as Fast takes ownership of the consumer.
75+
* It is a Severe one to only take into account those logs higher than threashold
4976
*/
50-
utils::event::LogSevereEventHandler* log_consumer_;
77+
utils::event::LogSevereEventHandler log_consumer_;
78+
79+
//! Expected minimum number of logs.
80+
unsigned int expected_severe_logs_;
5181

52-
uint32_t expected_severe_logs_;
53-
uint32_t max_severe_logs_;
82+
//! Expected maximum number of logs.
83+
unsigned int max_severe_logs_;
5484
};
5585

5686
/**
@@ -70,11 +100,11 @@ class LogChecker
70100
*/
71101
#define INSTANTIATE_LOG_TESTER(threshold, expected, max) \
72102
std::unique_ptr< \
73-
eprosima::utils::test::LogChecker, \
74-
std::function<void(eprosima::utils::test::LogChecker*)>> \
103+
eprosima::utils::testing::LogChecker, \
104+
std::function<void(eprosima::utils::testing::LogChecker*)>> \
75105
log_tester( \
76-
new eprosima::utils::test::LogChecker(threshold, expected, max), \
77-
[](eprosima::utils::test::LogChecker* t){ ASSERT_TRUE( t->check_valid()); delete t; \
106+
new eprosima::utils::testing::LogChecker(threshold, expected, max), \
107+
[](eprosima::utils::testing::LogChecker* t){ ASSERT_TRUE( t->check_valid()); delete t; \
78108
})
79109

80110
/**
@@ -83,6 +113,6 @@ class LogChecker
83113
*/
84114
#define DEFAULT_LOG_TESTER INSTANTIATE_LOG_TESTER(eprosima::utils::Log::Kind::Warning, 0, 0)
85115

86-
} /* namespace test */
116+
} /* namespace testing */
87117
} /* namespace utils */
88118
} /* namespace eprosima */
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/**
16+
* @file LogConsumerConnection.cpp
17+
*
18+
*/
19+
20+
#include <cpp_utils/Log.hpp>
21+
#include <cpp_utils/exception/InitializationException.hpp>
22+
23+
#include "event/logging/LogConsumerConnection.hpp"
24+
25+
namespace eprosima {
26+
namespace utils {
27+
namespace event {
28+
29+
LogConsumerConnection::LogConsumerConnection(
30+
LesseePtr<LogConsumerConnectionCallbackType>&& callback)
31+
: callback_(std::move(callback))
32+
{
33+
// Do nothing
34+
}
35+
36+
void LogConsumerConnection::Consume(
37+
const utils::Log::Entry& entry)
38+
{
39+
// Check whether the callback still exists
40+
auto callback_persistent = callback_.lock();
41+
42+
if (callback_persistent)
43+
{
44+
// In case it still exists, call it
45+
callback_persistent->operator ()(
46+
entry);
47+
}
48+
}
49+
50+
} /* namespace event */
51+
} /* namespace utils */
52+
} /* namespace eprosima */
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
/**
16+
* @file LogConsumerConnection.hpp
17+
*/
18+
19+
#pragma once
20+
21+
#include <atomic>
22+
#include <functional>
23+
24+
#include <cpp_utils/Log.hpp>
25+
#include <cpp_utils/event/LogEventHandler.hpp>
26+
#include <cpp_utils/memory/owner_ptr.hpp>
27+
#include <cpp_utils/library/library_dll.h>
28+
29+
namespace eprosima {
30+
namespace utils {
31+
namespace event {
32+
33+
/**
34+
* This class represents a \c LogConsumer that will be registered in Fast DDS Log as a unique_ptr and with each
35+
* \c Entry consumed it will call a shared function from a \c LogEventHandler .
36+
* As long as the EventHandler exists, it will manage these callbacks. When it dies, this object ptr to the function
37+
* will no longer be valid and thus it will do nothing.
38+
*/
39+
class LogConsumerConnection : public utils::LogConsumer
40+
{
41+
public:
42+
43+
//! Construct this class with a Lessee from the actual shared ptr.
44+
CPP_UTILS_DllAPI LogConsumerConnection(
45+
LesseePtr<LogConsumerConnectionCallbackType>&& callback);
46+
47+
//! Default destructor
48+
CPP_UTILS_DllAPI ~LogConsumerConnection() noexcept = default;
49+
50+
/**
51+
* @brief Implements \c LogConsumer \c Consume method.
52+
*
53+
* This will call \c callback_ as longs as it is valid.
54+
* Notice that while calling it the function could not be removed, as it will be guarded from a \c GuardedPtr .
55+
*
56+
* @param entry entry to consume
57+
*/
58+
CPP_UTILS_DllAPI void Consume(
59+
const utils::Log::Entry& entry) override;
60+
61+
protected:
62+
63+
//! Lessee to the shared callback object.
64+
LesseePtr<LogConsumerConnectionCallbackType> callback_;
65+
};
66+
67+
} /* namespace event */
68+
} /* namespace utils */
69+
} /* namespace eprosima */

0 commit comments

Comments
 (0)