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;
187-
186+ client = nullptr ;
187+
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 ];
207- }
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
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__;
214200 }
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__;
212+ }
213+ }
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");
224- }
225- currentMode = OutputMode::stdout;
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+ }
267+ }
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,8 +304,60 @@ class InfoLogger::Impl
258304 raw,
259305 none };
260306
261- OutputMode currentMode; // current option for output
262-
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+ if (s == nullptr ) {
317+ throw __LINE__;
318+ }
319+ out.mode = OutputMode::none;
320+ out.path = " " ;
321+ if (!strcmp (s," stdout" )) {
322+ out.mode = OutputMode::stdout;
323+ } else if (!strncmp (s," file" , 4 )) {
324+ out.mode = OutputMode::file;
325+ if (s[4 ] == ' :' ) {
326+ out.path = std::string (&s[5 ]);
327+ } else {
328+ out.path = " ./log.txt" ;
329+ }
330+ } else if (!strcmp (s," infoLoggerD" )) {
331+ out.mode = OutputMode::infoLoggerD;
332+ } else if (!strcmp (s," raw" )) {
333+ out.mode = OutputMode::raw;
334+ } else if (!strcmp (s," none" )) {
335+ out.mode = OutputMode::none;
336+ } else {
337+ throw __LINE__;
338+ }
339+ return ;
340+ };
341+
342+ const char * getStringFromMode (OutputMode m) {
343+ if (m==OutputMode::stdout) {
344+ return " stdout" ;
345+ } else if (m==OutputMode::file) {
346+ return " file" ;
347+ } else if (m==OutputMode::infoLoggerD) {
348+ return " infoLoggerD" ;
349+ } else if (m==OutputMode::none) {
350+ return " none" ;
351+ }
352+ return " unknown" ;
353+ }
354+
355+ OutputStream currentMode; // current option for output
356+ OutputStream mainMode = {OutputMode::infoLoggerD, " " }; // main output mode
357+ OutputStream fallbackMode = {OutputMode::stdout, " " }; // in case main mode is not available
358+
359+ bool verbose = 0 ; // in verbose mode, more info printed on stdout
360+
263361 // / Log a message, with a list of arguments of type va_list.
264362 // / \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.
265363 // / \param ap Variable list of arguments (c.f. vprintf)
@@ -285,7 +383,7 @@ class InfoLogger::Impl
285383 void refreshDefaultMsg ();
286384 infoLog_msg_t defaultMsg; // < default log message (in particular, to complete optionnal fields)
287385
288- InfoLoggerClient* client; // < entity to communicate with local infoLoggerD
386+ InfoLoggerClient* client = nullptr ; // < entity to communicate with local infoLoggerD
289387 SimpleLog stdLog; // < object to output messages to stdout/file
290388
291389 bool isRedirecting = false ; // state of stdout/stderr redirection
@@ -561,7 +659,7 @@ int InfoLogger::Impl::pushMessage(const InfoLoggerMessageOption& options, const
561659 // on error, close connection / use stdout / buffer messages in memory ?
562660 }
563661
564- if ((currentMode == OutputMode::stdout) || (currentMode == OutputMode::file)) {
662+ if ((currentMode. mode == OutputMode::stdout) || (currentMode. mode == OutputMode::file)) {
565663 char buffer[LOG_MAX_SIZE];
566664 msgHelper.MessageToText (&msg, buffer, sizeof (buffer), InfoLoggerMessageHelper::Format::Simple);
567665
@@ -582,7 +680,7 @@ int InfoLogger::Impl::pushMessage(const InfoLoggerMessageOption& options, const
582680 }
583681
584682 // raw output: infoLogger protocol to stdout
585- if (currentMode == OutputMode::raw) {
683+ if (currentMode. mode == OutputMode::raw) {
586684 char buffer[LOG_MAX_SIZE];
587685 msgHelper.MessageToText (&msg, buffer, sizeof (buffer), InfoLoggerMessageHelper::Format::Encoded);
588686 puts (buffer);
@@ -625,7 +723,15 @@ int InfoLogger::Impl::logV(const InfoLoggerMessageOption& options, const InfoLog
625723
626724InfoLogger::InfoLogger ()
627725{
628- mPimpl = std::make_unique<InfoLogger::Impl>();
726+ mPimpl = std::make_unique<InfoLogger::Impl>(" " );
727+ if (mPimpl == NULL ) {
728+ throw __LINE__;
729+ }
730+ }
731+
732+ InfoLogger::InfoLogger (const std::string &options)
733+ {
734+ mPimpl = std::make_unique<InfoLogger::Impl>(options);
629735 if (mPimpl == NULL ) {
630736 throw __LINE__;
631737 }
0 commit comments