30
30
31
31
using namespace OpenSim ;
32
32
33
+ static void initializeLogger (spdlog::logger& l) {
34
+ l.set_level (spdlog::level::info);
35
+ l.set_pattern (" %v" );
36
+ }
37
+
33
38
// cout logger will be initialized during static initialization time
34
- static std::shared_ptr<spdlog::logger> cout_logger = []() {
35
- std::shared_ptr<spdlog::logger> logger = spdlog::stdout_color_mt (" cout" );
36
- logger->set_level (spdlog::level::info);
37
- logger->set_pattern (" %v" );
38
- return logger;
39
- }();
39
+ static std::shared_ptr<spdlog::logger> coutLogger =
40
+ spdlog::stdout_color_mt (" cout" );
40
41
41
42
// default logger will be initialized during static initialization time
42
- static std::shared_ptr<spdlog::logger> default_logger = []() {
43
- std::shared_ptr<spdlog::logger> logger = spdlog::default_logger ();
44
- logger->set_level (spdlog::level::info);
45
- logger->set_pattern (" [%l] %v" );
46
- return logger;
47
- }();
48
-
49
- // this initialization will also happen during static initialization time
50
- static bool other_init = []() {
43
+ static std::shared_ptr<spdlog::logger> defaultLogger =
44
+ spdlog::default_logger ();
45
+
46
+ // this function returns a dummy value so that it can be used in an assignment
47
+ // expression (below) that *must* be executed in-order at static init time
48
+ static bool initializeLogging () {
49
+ initializeLogger (*coutLogger);
50
+ initializeLogger (*defaultLogger);
51
51
spdlog::flush_on (spdlog::level::info);
52
52
return true ;
53
- }();
53
+ }
54
+
55
+ // initialization of this variable will have the side-effect of completing the
56
+ // initialization of logging
57
+ static bool otherStaticInit = initializeLogging();
54
58
55
- // the file log sink (e.g. `opensim.log`) is lazily initialized - potentially
56
- // during static initialization time.
59
+ // the file log sink (e.g. `opensim.log`) is lazily initialized.
57
60
//
58
- // it is only initialized when the first log message is about to be written.
59
- // Users *may* disable this functionality before the first log message is
60
- // written.
61
+ // it is only initialized when the first log message is about to be written to
62
+ // it. Users *may* disable this functionality before the first log message is
63
+ // written (or disable it statically, by setting OPENSIM_DISABLE_LOG_FILE)
61
64
static std::shared_ptr<spdlog::sinks::basic_file_sink_mt> m_filesink = nullptr ;
62
65
63
66
// if a user manually calls `Logger::(remove|add)FileSink`, auto-initialization
64
- // should be entirely disabled
65
- static bool filesink_auto_initialization_disabled = false ;
67
+ // should be disabled. Manual usage "overrides" lazy auto-initialization.
68
+ static bool fileSinkAutoInitDisabled = false ;
66
69
67
- // when auto-initialization of the file log *may* happen, ensure that it can
68
- // only happen exactly once globally
70
+ // attempt to auto-initialize the file log, if applicable
69
71
static bool initFileLoggingAsNeeded () {
70
72
#ifdef OPENSIM_DISABLE_LOG_FILE
71
73
// software builders may want to statically ensure that automatic file logging
72
74
// *cannot* happen - even during static initialization. This compiler define
73
75
// outright disables the behavior, which is important in Windows applications
74
- // that run multiple instances of OpenSim-linked binaries. There, the logs may
75
- // collide and cause a "multiple processes cannot open the same file" error).
76
+ // that run multiple instances of OpenSim-linked binaries. In Windows, the
77
+ // logs files collide and cause a "multiple processes cannot open the same
78
+ // file" error).
76
79
return true ;
77
80
#else
78
81
static bool initialized = []() {
79
- if (filesink_auto_initialization_disabled ) {
82
+ if (fileSinkAutoInitDisabled ) {
80
83
return true ;
81
84
}
82
85
Logger::addFileSink ();
@@ -91,30 +94,30 @@ return true;
91
94
// it should perform lazy initialization of the file sink
92
95
spdlog::logger& Logger::getCoutLogger () {
93
96
initFileLoggingAsNeeded ();
94
- return *cout_logger ;
97
+ return *coutLogger ;
95
98
}
96
99
97
100
// this function is only called when the caller is about to log something, so
98
101
// it should perform lazy initialization of the file sink
99
102
spdlog::logger& Logger::getDefaultLogger () {
100
103
initFileLoggingAsNeeded ();
101
- return *default_logger ;
104
+ return *defaultLogger ;
102
105
}
103
106
104
107
static void addSinkInternal (std::shared_ptr<spdlog::sinks::sink> sink) {
105
- cout_logger ->sinks ().push_back (sink);
106
- default_logger ->sinks ().push_back (sink);
108
+ coutLogger ->sinks ().push_back (sink);
109
+ defaultLogger ->sinks ().push_back (sink);
107
110
}
108
111
109
112
static void removeSinkInternal (const std::shared_ptr<spdlog::sinks::sink> sink)
110
113
{
111
114
{
112
- auto & sinks = default_logger ->sinks ();
115
+ auto & sinks = defaultLogger ->sinks ();
113
116
auto new_end = std::remove (sinks.begin (), sinks.end (), sink);
114
117
sinks.erase (new_end, sinks.end ());
115
118
}
116
119
{
117
- auto & sinks = cout_logger ->sinks ();
120
+ auto & sinks = coutLogger ->sinks ();
118
121
auto new_end = std::remove (sinks.begin (), sinks.end (), sink);
119
122
sinks.erase (new_end, sinks.end ());
120
123
}
@@ -150,7 +153,7 @@ void Logger::setLevel(Level level) {
150
153
}
151
154
152
155
Logger::Level Logger::getLevel () {
153
- switch (default_logger ->level ()) {
156
+ switch (defaultLogger ->level ()) {
154
157
case spdlog::level::off: return Level::Off;
155
158
case spdlog::level::critical: return Level::Critical;
156
159
case spdlog::level::err: return Level::Error;
@@ -210,7 +213,7 @@ bool Logger::shouldLog(Level level) {
210
213
default :
211
214
OPENSIM_THROW (Exception, " Internal error." );
212
215
}
213
- return default_logger ->should_log (spdlogLevel);
216
+ return defaultLogger ->should_log (spdlogLevel);
214
217
}
215
218
216
219
void Logger::addFileSink (const std::string& filepath) {
@@ -220,10 +223,10 @@ void Logger::addFileSink(const std::string& filepath) {
220
223
//
221
224
// downstream callers would find it quite surprising if the auto-initializer
222
225
// runs *after* they manually specify a log, so just disable it
223
- filesink_auto_initialization_disabled = true ;
226
+ fileSinkAutoInitDisabled = true ;
224
227
225
228
if (m_filesink) {
226
- default_logger ->warn (" Already logging to file '{}'; log file not added. Call "
229
+ defaultLogger ->warn (" Already logging to file '{}'; log file not added. Call "
227
230
" removeFileSink() first." , m_filesink->filename ());
228
231
return ;
229
232
}
@@ -235,7 +238,7 @@ void Logger::addFileSink(const std::string& filepath) {
235
238
std::make_shared<spdlog::sinks::basic_file_sink_mt>(filepath);
236
239
}
237
240
catch (...) {
238
- default_logger ->warn (" Can't open file '{}' for writing. Log file will not be created. "
241
+ defaultLogger ->warn (" Can't open file '{}' for writing. Log file will not be created. "
239
242
" Check that you have write permissions to the specified path." ,
240
243
filepath);
241
244
return ;
@@ -251,7 +254,7 @@ void Logger::removeFileSink() {
251
254
// callers will be surpised if, after calling this method, auto
252
255
// initialization happens afterwards and the log file still exists - even
253
256
// if they called it to remove some manually-specified log
254
- filesink_auto_initialization_disabled = true ;
257
+ fileSinkAutoInitDisabled = true ;
255
258
256
259
if (m_filesink == nullptr ) {
257
260
return ;
0 commit comments