Flow 1.0.0
Flow project: Full implementation reference.
log.cpp
Go to the documentation of this file.
1/* Flow
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
19#include "flow/log/log.hpp"
20#include "flow/error/error.hpp"
22
23namespace flow::log
24{
25
26// Global initializations.
27
28boost::thread_specific_ptr<Msg_metadata> this_thread_sync_msg_metadata_ptr;
29
30// Static initializations.
31
32boost::thread_specific_ptr<std::string> Logger::s_this_thread_nickname_ptr;
33
34// Logger implementations.
35
37 bool also_set_os_name) // Static.
38{
39 using std::string;
40 using boost::system::system_category;
41 using ::pthread_setname_np;
42 using ::pthread_self;
43
44 /* Either set or delete (0 means no nickname, which is the original state of things).
45 * Note: This value is saved in a thread-local fashion. This has no effect on the
46 * value of s_this_thread_nickname.get() or dereference thereof in any thread except
47 * the one in which we currently execute. */
48 s_this_thread_nickname_ptr.reset(thread_nickname.empty()
49 ? 0
50 : new string(thread_nickname));
51
52 // Log about it if given an object capable of logging about itself.
53 if (logger_ptr)
54 {
55 FLOW_LOG_SET_CONTEXT(logger_ptr, Flow_log_component::S_LOG);
56 FLOW_LOG_INFO("Set new thread nickname for current thread ID "
57 "[" << util::this_thread::get_id() << "].");
58 }
59
60 if (also_set_os_name)
61 {
62#ifndef FLOW_OS_LINUX
63# error "this_thread_set_logged_nickname() also_set_os_name implementation is for Linux only."
64 /* `man pthread_setname_np` works in Darwin/Mac but is very short, and there is no `man pthread_getname_np`.
65 * It might work fine for Mac, but it's untested, and I (ygoldfel) didn't want to deal with it yet.
66 * In particular it's unclear if the MAX_PTHREAD_NAME_SZ would apply (it's not in `man` for Mac)... etc.
67 * @todo Look into it. */
68#endif
69 string os_name = thread_nickname.empty() ? util::ostream_op_string(util::this_thread::get_id())
70 : string(thread_nickname);
71
72 // See `man pthread_setname_np`. There is a hard limit on the length of the name, and it is:
73 constexpr size_t MAX_PTHREAD_NAME_SZ = 15;
74 if (os_name.size() > MAX_PTHREAD_NAME_SZ)
75 {
76 // As advertised: Truncate from the front to increase chance resulting name is still disambiguated from others.
77 os_name.erase(0, os_name.size() - MAX_PTHREAD_NAME_SZ);
78 }
79
80 const auto result_code = pthread_setname_np(pthread_self(), os_name.c_str());
81
82 // Log about it if given an object capable of logging about itself.
83 if (logger_ptr)
84 {
85 FLOW_LOG_SET_CONTEXT(logger_ptr, Flow_log_component::S_LOG);
86 if (result_code == -1)
87 {
88 const Error_code sys_err_code(errno, system_category());
89 FLOW_LOG_WARNING("Unable to set OS thread name to [" << os_name << "], possibly truncated from the front "
90 "to [" << MAX_PTHREAD_NAME_SZ << "] characters, via pthread_setname_np(). "
91 "This should only occur due to an overlong name, which we guard against, so this is "
92 "highly unexpected. Details follow.");
94 }
95 else
96 {
97 FLOW_LOG_INFO("OS thread name has been set to [" << os_name << "], possibly truncated from the front "
98 "to [" << MAX_PTHREAD_NAME_SZ << "] characters.");
99 }
100 }
101
102 // We could continue, but it's indicative of a newly-broken API or misunderstanding of `man`: better to be alerted.
103 assert(result_code != -1);
104 } // if (also_set_os_name)
105} // Logger::this_thread_set_logged_nickname()
106
107std::ostream& Logger::this_thread_logged_name_os_manip(std::ostream& os) // Static.
108{
109 // Reminder: we are an ostream manipulator, invoked like flush or endl: os << flush;
110
111 /* If there's a thread nickname, output that. Otherwise default to actual thread ID.
112 * ATTN: This must be consistent with behavior in set_thread_info*().
113 * We could also just use the latter here, but the following is a bit quicker. @todo Reconsider maybe. */
114
115 auto const this_thread_nickname_ptr = s_this_thread_nickname_ptr.get();
116 if (this_thread_nickname_ptr)
117 {
118 return os << (*this_thread_nickname_ptr);
119 }
120 // else
121 return os << util::this_thread::get_id();
122}
123
124void Logger::set_thread_info(std::string* call_thread_nickname, flow::util::Thread_id* call_thread_id) // Static.
125{
126 assert(call_thread_nickname);
127 assert(call_thread_id);
128
129 /* If there's a thread nickname, output that. Otherwise default to actual thread ID.
130 * ATTN: This must be consistent with behavior in this_thread_logged_name_os_manip(). */
131
132 auto const this_thread_nickname_ptr = s_this_thread_nickname_ptr.get();
133 if (this_thread_nickname_ptr)
134 {
135 *call_thread_nickname = (*this_thread_nickname_ptr);
136 }
137 else
138 {
139 *call_thread_id = util::this_thread::get_id();
140 }
141}
142
144{
145 assert(msg_metadata);
146 set_thread_info(&msg_metadata->m_call_thread_nickname, &msg_metadata->m_call_thread_id);
147}
148
149std::ostream* Logger::this_thread_ostream() const
150{
151 // Grab the stream used for the current thread by this particular Logger.
153}
154
155// Component implementations.
156
158 m_payload_type_or_null(0) // <=> empty() == true.
159{
160 // That's it. m_payload_enum_raw_value is uninitialized.
161}
162
163Component::Component(const Component& src) = default;
164Component::Component(Component&& src_moved) = default; // Note it doesn't empty()-ify src_moved.
165Component& Component::operator=(const Component& src) = default;
166Component& Component::operator=(Component&& src_moved) = default; // Note it doesn't empty()-ify src_moved.
167
169{
171}
172
173const std::type_info& Component::payload_type() const
174{
175 assert(!empty()); // We advertised undefined behavior in this case.
177}
178
179std::type_index Component::payload_type_index() const
180{
181 using std::type_index;
182
183 // See perf discussion in our doc header (regarding whether there's any computational cost to this).
184 return type_index(payload_type());
185}
186
188{
189 assert(!empty()); // We advertised undefined behavior in this case.
191}
192
193// Log_context implementations.
194
196 m_logger(logger)
197{
198 // Nothing.
199}
200
201Log_context::Log_context(const Log_context& src) = default;
202
204{
205 operator=(std::move(src));
206}
207
208Log_context& Log_context::operator=(const Log_context& src) = default;
209
211{
212 using std::swap;
213
214 if (&src != this)
215 {
216 m_logger = 0;
218
219 swap(*this, src);
220 }
221 return *this;
222}
223
225{
226 return m_logger;
227}
228
230{
231 return m_component;
232}
233
235{
236 using std::swap;
237
238 swap(m_logger, other.m_logger);
240}
241
242void swap(Log_context& val1, Log_context& val2)
243{
244 val1.swap(val2);
245}
246
247// Sev implementations.
248
249std::ostream& operator<<(std::ostream& os, Sev val)
250{
251 // Note: Must satisfy istream_to_enum() requirements.
252 switch (val)
253 {
254 case Sev::S_NONE: return os << "NONE";
255 case Sev::S_FATAL: return os << "FATAL";
256 case Sev::S_ERROR: return os << "ERROR";
257 case Sev::S_WARNING: return os << "WARNING";
258 case Sev::S_INFO: return os << "INFO";
259 case Sev::S_DEBUG: return os << "DEBUG";
260 case Sev::S_TRACE: return os << "TRACE";
261 case Sev::S_DATA: return os << "DATA";
262 case Sev::S_END_SENTINEL: assert(false && "Should not be printing sentinel.");
263 }
264
265 assert(false && "Looks like a corrupt/sentinel log::Sev value. gcc would've caught an incomplete switch().");
266 return os;
267}
268
269std::istream& operator>>(std::istream& is, Sev& val)
270{
271 // Range [NONE, END_SENTINEL); no match => NONE; allow for number instead of ostream<< string; case-insensitive.
273 return is;
274}
275
276// Free function implementations.
277
279{
281
282 if (logger_ptr)
283 {
285 }
286}
287
288size_t deep_size(const Msg_metadata& val)
289{
290 // We're following the loose pattern explained at the end of Async_file_logger::mem_cost().
291
292 using util::deep_size;
293
294 /* Reminder: exclude sizeof(val); include only non-shallow memory used on val's behalf; so
295 * sum of deep_size(X), for each X that is (1) a member of Msg_metadata; and (2) has a deep_size(X) free function.
296 * As of this writing there is just one: */
298}
299
300} // namespace flow::log
A light-weight class, each object storing a component payload encoding an enum value from enum type o...
Definition: log.hpp:840
Component & operator=(const Component &src)
Overwrites *this with a copy of src.
unsigned int enum_raw_t
The type Payload must be enum class Payload : enum_raw_t: an enum type encoded via this integer type.
Definition: log.hpp:845
std::type_info const * m_payload_type_or_null
The typeid() of the Payload passed to the 1-arg constructor; if 0-arg ctor was used (empty() is true)...
Definition: log.hpp:1024
const std::type_info & payload_type() const
Returns typeid(Payload), where Payload was the template param used when calling the originating one-a...
Definition: log.cpp:173
bool empty() const
Returns true if *this is as if default-constructed (a null Component); false if as if constructed via...
Definition: log.cpp:168
enum_raw_t m_payload_enum_raw_value
The internally stored integer representation of the enum value passed to the 1-arg constructor; meani...
Definition: log.hpp:1030
enum_raw_t payload_enum_raw_value() const
Returns the numeric value of the enum payload stored by this Component, originating in the one-arg co...
Definition: log.cpp:187
Component()
Constructs a Component that stores no payload; meaning an unspecified-component Component that return...
Definition: log.cpp:157
std::type_index payload_type_index() const
Convenience accessor that returns std::type_index(payload_type()), which can be used most excellently...
Definition: log.cpp:179
Convenience class that simply stores a Logger and/or Component passed into a constructor; and returns...
Definition: log.hpp:1619
Log_context & operator=(const Log_context &src)
Assignment operator that behaves similarly to the copy constructor.
const Component & get_log_component() const
Returns reference to the stored Component object, particularly as many FLOW_LOG_*() macros expect.
Definition: log.cpp:229
void swap(Log_context &other)
Swaps Logger pointers and Component objects held by *this and other.
Definition: log.cpp:234
Component m_component
The held Component object. Making the object non-const to allow operator=() to work.
Definition: log.hpp:1721
Log_context(Logger *logger=0)
Constructs Log_context by storing the given pointer to a Logger and a null Component.
Definition: log.cpp:195
Logger * m_logger
The held Logger pointer. Making the pointer itself non-const to allow operator=() to work.
Definition: log.hpp:1719
Logger * get_logger() const
Returns the stored Logger pointer, particularly as many FLOW_LOG_*() macros expect.
Definition: log.cpp:224
Interface that the user should implement, passing the implementing Logger into logging classes (Flow'...
Definition: log.hpp:1291
static void set_thread_info(std::string *call_thread_nickname, flow::util::Thread_id *call_thread_id)
Same as set_thread_info_in_msg_metadata() but targets the given two variables as opposed to a Msg_met...
Definition: log.cpp:124
static void set_thread_info_in_msg_metadata(Msg_metadata *msg_metadata)
Loads msg_metadata->m_call_thread_nickname (if set) or else msg_metadata->m_call_thread_id,...
Definition: log.cpp:143
static boost::thread_specific_ptr< std::string > s_this_thread_nickname_ptr
Thread-local storage for each thread's logged name (null pointer, which is default,...
Definition: log.hpp:1561
static void this_thread_set_logged_nickname(util::String_view thread_nickname=util::String_view(), Logger *logger_ptr=0, bool also_set_os_name=true)
Sets or unsets the current thread's logging-worthy string name; optionally sets the OS thread name (s...
Definition: log.cpp:36
static std::ostream & this_thread_logged_name_os_manip(std::ostream &os)
ostream manipulator function that, if output via operator<< to an ostream, will cause the current thr...
Definition: log.cpp:107
std::ostream * this_thread_ostream() const
Returns the stream dedicated to the executing thread and this Logger, so that the caller can apply st...
Definition: log.cpp:149
static Thread_local_string_appender * get_this_thread_string_appender(const util::Unique_id_holder &source_obj_id)
Returns a pointer to the exactly one Thread_local_string_appender object that is accessible from the ...
std::ostream * appender_ostream()
Same as fresh_appender_ostream() but does not clear the result string, enabling piecemeal writing to ...
#define FLOW_ERROR_SYS_ERROR_LOG_WARNING()
Logs a warning about the (often errno-based or from a library) error code in sys_err_code.
Definition: error.hpp:269
#define FLOW_LOG_INFO(ARG_stream_fragment)
Logs an INFO message into flow::log::Logger *get_logger() with flow::log::Component get_log_component...
Definition: log.hpp:197
#define FLOW_LOG_WARNING(ARG_stream_fragment)
Logs a WARNING message into flow::log::Logger *get_logger() with flow::log::Component get_log_compone...
Definition: log.hpp:152
#define FLOW_LOG_SET_CONTEXT(ARG_logger_ptr, ARG_component_payload)
For the rest of the block within which this macro is instantiated, causes all FLOW_LOG_....
Definition: log.hpp:405
Flow module providing logging functionality.
std::ostream & operator<<(std::ostream &os, Sev val)
Serializes a log::Sev to a standard output stream.
Definition: log.cpp:249
void swap(Log_context &val1, Log_context &val2)
Log_context ADL-friendly swap: Equivalent to val1.swap(val2).
Definition: log.cpp:242
size_t deep_size(const Msg_metadata &val)
Estimate of memory footprint of the given value, including memory allocated on its behalf – but exclu...
Definition: log.cpp:288
std::istream & operator>>(std::istream &is, Sev &val)
Deserializes a log::Sev from a standard input stream.
Definition: log.cpp:269
Sev
Enumeration containing one of several message severity levels, ordered from highest to lowest.
Definition: log_fwd.hpp:224
@ S_DATA
Message satisfies Sev::S_TRACE description AND contains variable-length structure (like packet,...
@ S_TRACE
Message indicates any condition that may occur with great frequency (thus verbose if logged).
@ S_WARNING
Message indicates a "bad" condition that is not frequent enough to be of severity Sev::S_TRACE.
@ S_END_SENTINEL
Not an actual value but rather stores the highest numerical payload, useful for validity checks.
@ S_NONE
Sentinel log level that must not be specified for any actual message (at risk of undefined behavior s...
@ S_DEBUG
Message indicates a condition with, perhaps, no significant perf impact if enabled (like Sev::S_INFO)...
@ S_ERROR
Message indicates a "bad" condition with "worse" impact than that of Sev::S_WARNING.
@ S_INFO
Message indicates a not-"bad" condition that is not frequent enough to be of severity Sev::S_TRACE.
@ S_FATAL
Message indicates a "fatally bad" condition, such that the program shall imminently abort,...
void beautify_chrono_logger_this_thread(Logger *logger_ptr)
Sets certain chrono-related formatting on the given Logger in the current thread that results in a co...
Definition: log.cpp:278
boost::thread_specific_ptr< Msg_metadata > this_thread_sync_msg_metadata_ptr
Thread-local Msg_metadata object used by FLOW_LOG_WITHOUT_CHECKING() for an alleged perf bonus in the...
Definition: log.cpp:28
void beautify_chrono_ostream(std::ostream *os_ptr)
Sets certain chrono-related formatting on the given ostream that results in a consistent,...
Definition: util.cpp:173
Thread::id Thread_id
Short-hand for an OS-provided ID of a util::Thread.
Definition: util_fwd.hpp:90
Enum istream_to_enum(std::istream *is_ptr, Enum enum_default, Enum enum_sentinel, bool accept_num_encoding, bool case_sensitive, Enum enum_lowest)
Deserializes an enum class value from a standard input stream.
Definition: util.hpp:498
size_t deep_size(const std::string &val)
Estimate of memory footprint of the given value, including memory allocated on its behalf – but exclu...
Definition: util.cpp:186
std::string ostream_op_string(T const &... ostream_args)
Equivalent to ostream_op_to_string() but returns a new string by value instead of writing to the call...
Definition: util.hpp:356
Basic_string_view< char > String_view
Commonly used char-based Basic_string_view. See its doc header.
boost::system::error_code Error_code
Short-hand for a boost.system error code (which basically encapsulates an integer/enum error code and...
Definition: common.hpp:502
Simple data store containing all of the information generated at every logging call site by flow::log...
Definition: log.hpp:1048
util::Thread_id m_call_thread_id
Thread ID of the thread from which the log call was invoked; or a default-constructed (no-thread) suc...
Definition: log.hpp:1144
std::string m_call_thread_nickname
Thread nickname, as for Logger::this_thread_set_logged_nickname(), of the thread from which the log c...
Definition: log.hpp:1134