1919
2020#include " infoLoggerMessage.h"
2121#include " InfoLoggerClient.h"
22+ #include " infoLoggerUtils.h"
2223
2324#include < stdio.h>
2425#include < stdlib.h>
@@ -171,60 +172,105 @@ namespace AliceO2
171172namespace InfoLogger
172173{
173174
174- int infoLoggerDWarningDone = 0 ;
175-
176175// private class to isolate internal data from external interface
177176class InfoLogger ::Impl
178177{
179178 public:
180- Impl ()
179+ Impl (const std::string& options )
181180 {
182181 // initiate internal members
183182 magicTag = InfoLoggerMagicNumber;
184183 numberOfMessages = 0 ;
185184 currentStreamMessage.clear ();
186185 currentStreamOptions = undefinedMessageOption;
186+ client = nullptr ;
187187
188188 floodReset ();
189189
190190 if (infoLog_proto_init ()) {
191191 throw __LINE__;
192192 }
193193 refreshDefaultMsg ();
194- currentMode = OutputMode::infoLoggerD;
195-
196- const char * confEnv = getenv (" INFOLOGGER_MODE" );
197- if (confEnv != NULL ) {
198- if (!strcmp (confEnv, " stdout" )) {
199- currentMode = OutputMode::stdout;
200- } else if (!strcmp (confEnv, " infoLoggerD" )) {
201- currentMode = OutputMode::infoLoggerD;
202- } else if (!strncmp (confEnv, " file" , 4 )) {
203- currentMode = OutputMode::file;
204- const char * logFile = " ./log.txt" ;
205- if (confEnv[4 ] == ' :' ) {
206- logFile = &confEnv[5 ];
194+
195+ // option-processing routine
196+ auto processOptions = [&](std::string opt) {
197+ std::map<std::string, std::string> kv;
198+ if (getKeyValuePairsFromString (opt, kv)) {
199+ throw __LINE__;
200+ }
201+ for (auto & it : kv) {
202+ if (it.first == " outputMode" ) {
203+ getOutputStreamFromString (it.second .c_str (), mainMode);
204+ } else if (it.first == " outputModeFallback" ) {
205+ getOutputStreamFromString (it.second .c_str (), fallbackMode);
206+ } else if (it.first == " verbose" ) {
207+ verbose = atoi (it.second .c_str ());
208+ } else {
209+ // unknown option
210+ // printf("Unknown option %s\n",it.second.c_str());
211+ throw __LINE__;
207212 }
208- printf (" Logging to file %s\n " , logFile);
209- stdLog.setLogFile (logFile);
210- } else if (!strcmp (confEnv, " raw" )) {
211- currentMode = OutputMode::raw;
212- } else if (!strcmp (confEnv, " none" )) {
213- currentMode = OutputMode::none; // useful for benchmarks
214213 }
214+ return ;
215+ };
216+
217+ // parse options from constructor arg
218+ processOptions (options);
219+
220+ // parse options from environment
221+ const char * confEnvOptions = getenv (" INFOLOGGER_OPTIONS" );
222+ if (confEnvOptions != NULL ) {
223+ processOptions (confEnvOptions);
215224 }
216- client = nullptr ;
217- if (currentMode == OutputMode::infoLoggerD) {
218- client = new InfoLoggerClient;
219- if ((client == nullptr ) || (!client->isOk ())) {
220- // fallback to stdout if infoLoggerD not available
221- if (!infoLoggerDWarningDone) {
222- infoLoggerDWarningDone = 1 ;
223- // fprintf(stderr,"infoLoggerD not available, falling back to stdout logging\n");
225+
226+ const char * confEnvMode = getenv (" INFOLOGGER_MODE" );
227+ if (confEnvMode != NULL ) {
228+ getOutputStreamFromString (confEnvMode, mainMode);
229+ }
230+
231+ // init main output and fallbacks if needed
232+ currentMode = mainMode;
233+ for (int it = 0 ; it < 3 ; it++) {
234+ if (it == 0 ) {
235+ currentMode = mainMode;
236+ } else if (it == 1 ) {
237+ currentMode = fallbackMode;
238+ } else {
239+ currentMode.mode = OutputMode::none;
240+ currentMode.path = " /dev/null" ;
241+ }
242+ if (verbose) {
243+ printf (" Using output mode %s\n " , getStringFromMode (currentMode.mode ));
244+ }
245+
246+ if (currentMode.mode == OutputMode::file) {
247+ if (verbose) {
248+ printf (" Logging to file %s\n " , currentMode.path .c_str ());
249+ }
250+ if (stdLog.setLogFile (currentMode.path .c_str (), 0 , 4 , 0 ) == 0 ) {
251+ break ;
252+ }
253+ } else if (currentMode.mode == OutputMode::stdout) {
254+ if (stdLog.setLogFile (nullptr ) == 0 ) {
255+ break ;
256+ }
257+ } else if (currentMode.mode == OutputMode::none) {
258+ if (stdLog.setLogFile (currentMode.path .c_str ()) == 0 ) {
259+ break ;
260+ }
261+ } else if (currentMode.mode == OutputMode::infoLoggerD) {
262+ client = new InfoLoggerClient;
263+ if (client != nullptr ) {
264+ if (client->isOk ()) {
265+ break ;
266+ }
224267 }
225- currentMode = OutputMode::stdout;
268+ }
269+ if (verbose) {
270+ printf (" Output to %s failed\n " , getStringFromMode (currentMode.mode ));
226271 }
227272 }
273+
228274 // todo
229275 // switch mode based on configuration / environment
230276 // connect to client only on first message (or try again after timeout)
@@ -258,7 +304,61 @@ class InfoLogger::Impl
258304 raw,
259305 none };
260306
261- OutputMode currentMode; // current option for output
307+ struct OutputStream {
308+ OutputMode mode; // selected mode
309+ std::string path; // optional path (eg for 'file' mode)
310+ };
311+
312+ // convert a string to a member of the OutputMode enum
313+ // and sets filePath in case of the "file" mode
314+ // throw an integer error code on error
315+ void getOutputStreamFromString (const char * s, OutputStream& out)
316+ {
317+ if (s == nullptr ) {
318+ throw __LINE__;
319+ }
320+ out.mode = OutputMode::none;
321+ out.path = " " ;
322+ if (!strcmp (s, " stdout" )) {
323+ out.mode = OutputMode::stdout;
324+ } else if (!strncmp (s, " file" , 4 )) {
325+ out.mode = OutputMode::file;
326+ if (s[4 ] == ' :' ) {
327+ out.path = std::string (&s[5 ]);
328+ } else {
329+ out.path = " ./log.txt" ;
330+ }
331+ } else if (!strcmp (s, " infoLoggerD" )) {
332+ out.mode = OutputMode::infoLoggerD;
333+ } else if (!strcmp (s, " raw" )) {
334+ out.mode = OutputMode::raw;
335+ } else if (!strcmp (s, " none" )) {
336+ out.mode = OutputMode::none;
337+ } else {
338+ throw __LINE__;
339+ }
340+ return ;
341+ };
342+
343+ const char * getStringFromMode (OutputMode m)
344+ {
345+ if (m == OutputMode::stdout) {
346+ return " stdout" ;
347+ } else if (m == OutputMode::file) {
348+ return " file" ;
349+ } else if (m == OutputMode::infoLoggerD) {
350+ return " infoLoggerD" ;
351+ } else if (m == OutputMode::none) {
352+ return " none" ;
353+ }
354+ return " unknown" ;
355+ }
356+
357+ OutputStream currentMode; // current option for output
358+ OutputStream mainMode = { OutputMode::infoLoggerD, " " }; // main output mode
359+ OutputStream fallbackMode = { OutputMode::stdout, " " }; // in case main mode is not available
360+
361+ bool verbose = 0 ; // in verbose mode, more info printed on stdout
262362
263363 // / Log a message, with a list of arguments of type va_list.
264364 // / \param message NUL-terminated string message to push to the log system. It uses the same format as specified for printf(), and the function accepts additionnal formatting parameters.
@@ -285,7 +385,7 @@ class InfoLogger::Impl
285385 void refreshDefaultMsg ();
286386 infoLog_msg_t defaultMsg; // < default log message (in particular, to complete optionnal fields)
287387
288- InfoLoggerClient* client; // < entity to communicate with local infoLoggerD
388+ InfoLoggerClient* client = nullptr ; // < entity to communicate with local infoLoggerD
289389 SimpleLog stdLog; // < object to output messages to stdout/file
290390
291391 bool isRedirecting = false ; // state of stdout/stderr redirection
@@ -561,7 +661,7 @@ int InfoLogger::Impl::pushMessage(const InfoLoggerMessageOption& options, const
561661 // on error, close connection / use stdout / buffer messages in memory ?
562662 }
563663
564- if ((currentMode == OutputMode::stdout) || (currentMode == OutputMode::file)) {
664+ if ((currentMode. mode == OutputMode::stdout) || (currentMode. mode == OutputMode::file)) {
565665 char buffer[LOG_MAX_SIZE];
566666 msgHelper.MessageToText (&msg, buffer, sizeof (buffer), InfoLoggerMessageHelper::Format::Simple);
567667
@@ -582,7 +682,7 @@ int InfoLogger::Impl::pushMessage(const InfoLoggerMessageOption& options, const
582682 }
583683
584684 // raw output: infoLogger protocol to stdout
585- if (currentMode == OutputMode::raw) {
685+ if (currentMode. mode == OutputMode::raw) {
586686 char buffer[LOG_MAX_SIZE];
587687 msgHelper.MessageToText (&msg, buffer, sizeof (buffer), InfoLoggerMessageHelper::Format::Encoded);
588688 puts (buffer);
@@ -625,7 +725,15 @@ int InfoLogger::Impl::logV(const InfoLoggerMessageOption& options, const InfoLog
625725
626726InfoLogger::InfoLogger ()
627727{
628- mPimpl = std::make_unique<InfoLogger::Impl>();
728+ mPimpl = std::make_unique<InfoLogger::Impl>(" " );
729+ if (mPimpl == NULL ) {
730+ throw __LINE__;
731+ }
732+ }
733+
734+ InfoLogger::InfoLogger (const std::string& options)
735+ {
736+ mPimpl = std::make_unique<InfoLogger::Impl>(options);
629737 if (mPimpl == NULL ) {
630738 throw __LINE__;
631739 }
0 commit comments