1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4 
5 #include <Ice/LoggerAdminI.h>
6 #include <Ice/Initialize.h>
7 #include <Ice/Communicator.h>
8 #include <Ice/RemoteLogger.h>
9 #include <Ice/Properties.h>
10 #include <Ice/ObjectAdapter.h>
11 #include <Ice/Connection.h>
12 #include <Ice/LocalException.h>
13 #include <Ice/LoggerUtil.h>
14 
15 #include <set>
16 
17 using namespace Ice;
18 using namespace std;
19 
20 namespace
21 {
22 
23 const char* traceCategory = "Admin.Logger";
24 
25 class LoggerAdminI : public Ice::LoggerAdmin
26 #ifdef ICE_CPP11_MAPPING
27                    , public std::enable_shared_from_this<LoggerAdminI>
28 #endif
29 {
30 public:
31 
32     LoggerAdminI(const PropertiesPtr&);
33 
34 #ifdef ICE_CPP11_MAPPING
35     virtual void attachRemoteLogger(shared_ptr<RemoteLoggerPrx>, LogMessageTypeSeq,
36                                     StringSeq, Int, const Current&);
37 
38     virtual bool detachRemoteLogger(shared_ptr<RemoteLoggerPrx>, const Current&);
39 
40     virtual LogMessageSeq getLog(LogMessageTypeSeq, StringSeq, Int, string&, const Current&);
41 #else
42     virtual void attachRemoteLogger(const RemoteLoggerPrx&, const LogMessageTypeSeq&,
43                                     const StringSeq&, Int, const Current&);
44 
45     virtual bool detachRemoteLogger(const RemoteLoggerPrx&, const Current&);
46 
47     virtual LogMessageSeq getLog(const LogMessageTypeSeq&, const StringSeq&, Int, string&, const Current&);
48 #endif
49 
50     void destroy();
51 
52     vector<RemoteLoggerPrxPtr> log(const LogMessage&);
53 
54     void deadRemoteLogger(const RemoteLoggerPrxPtr&, const LoggerPtr&, const LocalException&, const string&);
55 
getTraceLevel() const56     int getTraceLevel() const
57     {
58         return _traceLevel;
59     }
60 
61 private:
62 
63     bool removeRemoteLogger(const RemoteLoggerPrxPtr&);
64 
65 #ifndef ICE_CPP11_MAPPING // C++98 mapping begin_init callback
66     void initCompleted(const AsyncResultPtr&);
67 #endif
68 
69     IceUtil::Mutex _mutex;
70     list<LogMessage> _queue;
71     int _logCount; // non-trace messages
72     const int _maxLogCount;
73     int _traceCount;
74     const int _maxTraceCount;
75     const int _traceLevel;
76 
77     list<LogMessage>::iterator _oldestTrace;
78     list<LogMessage>::iterator _oldestLog;
79 
80     struct ObjectIdentityCompare
81     {
operator ()__anonb661d1f90111::LoggerAdminI::ObjectIdentityCompare82         bool operator()(const RemoteLoggerPrxPtr& lhs, const RemoteLoggerPrxPtr& rhs) const
83         {
84             //
85             // Caller should make sure that proxies are never null
86             //
87             assert(lhs != 0 && rhs != 0);
88 
89             return lhs->ice_getIdentity() < rhs->ice_getIdentity();
90         }
91     };
92 
93     struct Filters
94     {
Filters__anonb661d1f90111::LoggerAdminI::Filters95         Filters(const LogMessageTypeSeq& m, const StringSeq& c) :
96             messageTypes(m.begin(), m.end()),
97             traceCategories(c.begin(), c.end())
98         {
99         }
100 
101         const set<LogMessageType> messageTypes;
102         const set<string> traceCategories;
103     };
104 
105     typedef map<RemoteLoggerPrxPtr, Filters, ObjectIdentityCompare> RemoteLoggerMap;
106 
107     struct GetRemoteLoggerMapKey
108     {
109         RemoteLoggerMap::key_type
operator ()__anonb661d1f90111::LoggerAdminI::GetRemoteLoggerMapKey110         operator()(const RemoteLoggerMap::value_type& val)
111         {
112             return val.first;
113         }
114     };
115 
116     RemoteLoggerMap _remoteLoggerMap;
117     CommunicatorPtr _sendLogCommunicator;
118     bool _destroyed;
119 };
120 ICE_DEFINE_PTR(LoggerAdminIPtr, LoggerAdminI);
121 
122 class Job : public IceUtil::Shared
123 {
124 public:
125 
Job(const vector<RemoteLoggerPrxPtr> & r,const LogMessage & l)126     Job(const vector<RemoteLoggerPrxPtr>& r, const LogMessage& l) :
127         remoteLoggers(r),
128         logMessage(l)
129     {
130     }
131 
132     const vector<RemoteLoggerPrxPtr> remoteLoggers;
133     const LogMessage logMessage;
134 };
135 typedef IceUtil::Handle<Job> JobPtr;
136 
137 class LoggerAdminLoggerI : public IceInternal::LoggerAdminLogger
138 #ifdef ICE_CPP11_MAPPING
139                          , public std::enable_shared_from_this<LoggerAdminLoggerI>
140 #endif
141 
142 {
143 public:
144 
145     LoggerAdminLoggerI(const PropertiesPtr&, const LoggerPtr&);
146 
147     virtual void print(const std::string&);
148     virtual void trace(const std::string&, const std::string&);
149     virtual void warning(const std::string&);
150     virtual void error(const std::string&);
151     virtual std::string getPrefix();
152     virtual LoggerPtr cloneWithPrefix(const std::string&);
153 
154     virtual ObjectPtr getFacet() const;
155 
156     virtual void destroy();
157 
getLocalLogger() const158     const LoggerPtr& getLocalLogger() const
159     {
160         return _localLogger;
161     }
162 
163     void run();
164 
165 private:
166 
167     void log(const LogMessage&);
168 #ifndef ICE_CPP11_MAPPING // C++98 mapping begin_log callback
169     void logCompleted(const AsyncResultPtr&);
170 #endif
171 
172     LoggerPtr _localLogger;
173     const LoggerAdminIPtr _loggerAdmin;
174 
175     IceUtil::Monitor<IceUtil::Mutex> _monitor;
176 
177     bool _destroyed;
178     IceUtil::ThreadPtr _sendLogThread;
179     std::deque<JobPtr> _jobQueue;
180 };
181 ICE_DEFINE_PTR(LoggerAdminLoggerIPtr, LoggerAdminLoggerI);
182 
183 class SendLogThread : public IceUtil::Thread
184 {
185 public:
186 
187     SendLogThread(const LoggerAdminLoggerIPtr&);
188 
189     virtual void run();
190 
191 private:
192 
193     LoggerAdminLoggerIPtr _logger;
194 };
195 
196 //
197 // Helper functions
198 //
199 
200 //
201 // Filter out messages from in/out logMessages list
202 //
203 void
filterLogMessages(LogMessageSeq & logMessages,const set<LogMessageType> & messageTypes,const set<string> & traceCategories,Int messageMax)204 filterLogMessages(LogMessageSeq& logMessages, const set<LogMessageType>& messageTypes,
205                   const set<string>& traceCategories, Int messageMax)
206 {
207     assert(!logMessages.empty() && messageMax != 0);
208 
209     //
210     // Filter only if one of the 3 filters is set; messageMax < 0 means "give me all"
211     // that match the other filters, if any.
212     //
213     if(!messageTypes.empty() || !traceCategories.empty() || messageMax > 0)
214     {
215         int count = 0;
216         LogMessageSeq::reverse_iterator p = logMessages.rbegin();
217         while(p != logMessages.rend())
218         {
219             bool keepIt = false;
220             if(messageTypes.empty() || messageTypes.count(p->type) != 0)
221             {
222                 if(p->type != ICE_ENUM(LogMessageType, TraceMessage) || traceCategories.empty() ||
223                    traceCategories.count(p->traceCategory) != 0)
224                 {
225                     keepIt = true;
226                 }
227             }
228 
229             if(keepIt)
230             {
231                 ++p;
232                 ++count;
233                 if(messageMax > 0 && count >= messageMax)
234                 {
235                     //
236                     // p.base() points to p "+1"; note that this invalidates p.
237                     //
238                     logMessages.erase(logMessages.begin(), p.base());
239                     break; // while
240                 }
241             }
242             else
243             {
244                 ++p;
245                 //
246                 // p.base() points to p "+1"; the erase invalidates p so we
247                 // need to rebuild it
248                 //
249                 p = LogMessageSeq::reverse_iterator(logMessages.erase(p.base()));
250             }
251         }
252     }
253     // else, don't need any filtering
254 }
255 
256 //
257 // Change this proxy's communicator, while keeping its invocation timeout
258 //
259 RemoteLoggerPrxPtr
changeCommunicator(const RemoteLoggerPrxPtr & prx,const CommunicatorPtr & communicator)260 changeCommunicator(const RemoteLoggerPrxPtr& prx, const CommunicatorPtr& communicator)
261 {
262     if(prx == 0)
263     {
264         return 0;
265     }
266 
267     RemoteLoggerPrxPtr result = ICE_UNCHECKED_CAST(RemoteLoggerPrx, communicator->stringToProxy(prx->ice_toString()));
268 
269     return result->ice_invocationTimeout(prx->ice_getInvocationTimeout());
270 }
271 
272 //
273 // Copies a set of properties
274 //
275 void
copyProperties(const string & prefix,const PropertiesPtr & from,const PropertiesPtr & to)276 copyProperties(const string& prefix, const PropertiesPtr& from, const PropertiesPtr& to)
277 {
278     PropertyDict dict = from->getPropertiesForPrefix(prefix);
279     for(PropertyDict::const_iterator p = dict.begin(); p != dict.end(); ++p)
280     {
281         to->setProperty(p->first, p->second);
282     }
283 }
284 
285 //
286 // Create communicator used to send logs
287 //
288 CommunicatorPtr
createSendLogCommunicator(const CommunicatorPtr & communicator,const LoggerPtr & logger)289 createSendLogCommunicator(const CommunicatorPtr& communicator, const LoggerPtr& logger)
290 {
291     InitializationData initData;
292     initData.logger = logger;
293     initData.properties = createProperties();
294 
295     PropertiesPtr mainProps = communicator->getProperties();
296 
297     copyProperties("Ice.Default.Locator", mainProps, initData.properties);
298     copyProperties("Ice.Plugin.IceSSL", mainProps, initData.properties);
299     copyProperties("IceSSL.", mainProps, initData.properties);
300 
301     StringSeq extraProps = mainProps->getPropertyAsList("Ice.Admin.Logger.Properties");
302 
303     if(!extraProps.empty())
304     {
305         for(vector<string>::iterator p = extraProps.begin(); p != extraProps.end(); ++p)
306         {
307             if(p->find("--") != 0)
308             {
309                 *p = "--" + *p;
310             }
311         }
312         initData.properties->parseCommandLineOptions("", extraProps);
313     }
314 
315     return initialize(initData);
316 }
317 
318 //
319 // LoggerAdminI
320 //
321 
LoggerAdminI(const PropertiesPtr & props)322 LoggerAdminI::LoggerAdminI(const PropertiesPtr& props) :
323     _logCount(0),
324     _maxLogCount(props->getPropertyAsIntWithDefault("Ice.Admin.Logger.KeepLogs", 100)),
325     _traceCount(0),
326     _maxTraceCount(props->getPropertyAsIntWithDefault("Ice.Admin.Logger.KeepTraces", 100)),
327     _traceLevel(props->getPropertyAsInt("Ice.Trace.Admin.Logger")),
328     _destroyed(false)
329 {
330     _oldestLog = _queue.end();
331     _oldestTrace = _queue.end();
332 }
333 
334 void
335 #ifdef ICE_CPP11_MAPPING
attachRemoteLogger(shared_ptr<RemoteLoggerPrx> prx,LogMessageTypeSeq messageTypes,StringSeq categories,Int messageMax,const Current & current)336 LoggerAdminI::attachRemoteLogger(shared_ptr<RemoteLoggerPrx> prx,
337                                  LogMessageTypeSeq messageTypes,
338                                  StringSeq categories,
339                                  Int messageMax,
340                                  const Current& current)
341 #else
342 LoggerAdminI::attachRemoteLogger(const RemoteLoggerPrx& prx,
343                                  const LogMessageTypeSeq& messageTypes,
344                                  const StringSeq& categories,
345                                  Int messageMax,
346                                  const Current& current)
347 #endif
348 {
349     if(!prx)
350     {
351         return; // can't send this null RemoteLogger anything!
352     }
353 
354     //
355     // In C++, LoggerAdminI does not keep a "logger" data member to avoid a hard-to-break circular
356     // reference, so we retrieve the logger from Current
357     //
358 
359     LoggerAdminLoggerIPtr logger = ICE_DYNAMIC_CAST(LoggerAdminLoggerI, current.adapter->getCommunicator()->getLogger());
360     if(!logger)
361     {
362         // Our logger is not installed - must be a bug
363         assert(0);
364         return;
365     }
366 
367     RemoteLoggerPrxPtr remoteLogger = prx->ice_twoway();
368 
369     Filters filters(messageTypes, categories);
370     LogMessageSeq initLogMessages;
371     {
372         IceUtil::Mutex::Lock lock(_mutex);
373 
374         if(!_sendLogCommunicator)
375         {
376             if(_destroyed)
377             {
378                 throw Ice::ObjectNotExistException(__FILE__, __LINE__);
379             }
380 
381             _sendLogCommunicator =
382                 createSendLogCommunicator(current.adapter->getCommunicator(), logger->getLocalLogger());
383         }
384 
385         if(!_remoteLoggerMap.insert(make_pair(changeCommunicator(remoteLogger, _sendLogCommunicator), filters)).second)
386         {
387             if(_traceLevel > 0)
388             {
389                 Trace trace(logger, traceCategory);
390                 trace << "rejecting `" << remoteLogger << "' with RemoteLoggerAlreadyAttachedException";
391             }
392 
393             throw RemoteLoggerAlreadyAttachedException();
394         }
395 
396         if(messageMax != 0)
397         {
398             initLogMessages = _queue; // copy
399         }
400     }
401 
402     if(_traceLevel > 0)
403     {
404         Trace trace(logger, traceCategory);
405         trace << "attached `" << remoteLogger << "'";
406     }
407 
408     if(!initLogMessages.empty())
409     {
410         filterLogMessages(initLogMessages, filters.messageTypes, filters.traceCategories, messageMax);
411     }
412 
413 #ifdef ICE_CPP11_MAPPING
414     try
415     {
416         auto self = shared_from_this();
417         remoteLogger->initAsync(logger->getPrefix(), initLogMessages,
418             [self, logger, remoteLogger]()
419             {
420                 if(self->_traceLevel > 1)
421                 {
422                     Trace trace(logger, traceCategory);
423                     trace << "init on `" << remoteLogger << "' completed successfully";
424                 }
425             },
426             [self, logger, remoteLogger](exception_ptr e)
427             {
428                 try
429                 {
430                     rethrow_exception(e);
431                 }
432                 catch(const Ice::LocalException& le)
433                 {
434                     self->deadRemoteLogger(remoteLogger, logger, le, "init");
435                 }
436             });
437     }
438     catch(const LocalException& ex)
439     {
440         deadRemoteLogger(remoteLogger, logger, ex, "init");
441         throw;
442     }
443 #else
444     CallbackPtr initCompletedCb = newCallback(this, &LoggerAdminI::initCompleted);
445     try
446     {
447         remoteLogger->begin_init(logger->getPrefix(), initLogMessages, initCompletedCb, logger);
448     }
449     catch(const LocalException& ex)
450     {
451         deadRemoteLogger(remoteLogger, logger, ex, "init");
452         throw;
453     }
454 #endif
455 }
456 
457 bool
458 #ifdef ICE_CPP11_MAPPING
detachRemoteLogger(shared_ptr<RemoteLoggerPrx> remoteLogger,const Current & current)459 LoggerAdminI::detachRemoteLogger(shared_ptr<RemoteLoggerPrx> remoteLogger, const Current& current)
460 #else
461 LoggerAdminI::detachRemoteLogger(const RemoteLoggerPrx& remoteLogger, const Current& current)
462 #endif
463 {
464     if(remoteLogger == 0)
465     {
466         return false;
467     }
468 
469     //
470     // No need to convert the proxy as we only use its identity
471     //
472     bool found = removeRemoteLogger(remoteLogger);
473 
474     if(_traceLevel > 0)
475     {
476         Trace trace(current.adapter->getCommunicator()->getLogger(), traceCategory);
477         if(found)
478         {
479             trace << "detached `" << remoteLogger << "'";
480         }
481         else
482         {
483             trace << "cannot detach `" << remoteLogger << "': not found";
484         }
485     }
486 
487     return found;
488 }
489 
490 LogMessageSeq
491 #ifdef ICE_CPP11_MAPPING
getLog(LogMessageTypeSeq messageTypes,StringSeq categories,Int messageMax,string & prefix,const Current & current)492 LoggerAdminI::getLog(LogMessageTypeSeq messageTypes, StringSeq categories,
493                      Int messageMax, string& prefix, const Current& current)
494 #else
495 LoggerAdminI::getLog(const LogMessageTypeSeq& messageTypes, const StringSeq& categories,
496                      Int messageMax, string& prefix, const Current& current)
497 #endif
498 {
499     LogMessageSeq logMessages;
500     {
501         IceUtil::Mutex::Lock lock(_mutex);
502 
503         if(messageMax != 0)
504         {
505             logMessages = _queue;
506         }
507     }
508 
509     LoggerPtr logger = current.adapter->getCommunicator()->getLogger();
510     prefix = logger->getPrefix();
511 
512     if(!logMessages.empty())
513     {
514         Filters filters(messageTypes, categories);
515         filterLogMessages(logMessages, filters.messageTypes, filters.traceCategories, messageMax);
516     }
517 
518     return logMessages;
519 }
520 
521 void
destroy()522 LoggerAdminI::destroy()
523 {
524     CommunicatorPtr sendLogCommunicator;
525     {
526         IceUtil::Mutex::Lock lock(_mutex);
527         if(!_destroyed)
528         {
529             _destroyed = true;
530             sendLogCommunicator = _sendLogCommunicator;
531             _sendLogCommunicator = 0;
532         }
533     }
534 
535     //
536     // Destroy outside lock to avoid deadlock when there are outstanding two-way log calls sent to
537     // remote loggers
538     //
539     if(sendLogCommunicator)
540     {
541         sendLogCommunicator->destroy();
542     }
543 }
544 
545 vector<RemoteLoggerPrxPtr>
log(const LogMessage & logMessage)546 LoggerAdminI::log(const LogMessage& logMessage)
547 {
548     vector<RemoteLoggerPrxPtr> remoteLoggers;
549 
550     IceUtil::Mutex::Lock lock(_mutex);
551 
552     //
553     // Put message in _queue
554     //
555     if((logMessage.type != ICE_ENUM(LogMessageType, TraceMessage) && _maxLogCount > 0) ||
556        (logMessage.type == ICE_ENUM(LogMessageType, TraceMessage) && _maxTraceCount > 0))
557     {
558         list<LogMessage>::iterator p = _queue.insert(_queue.end(), logMessage);
559 
560         if(logMessage.type != ICE_ENUM(LogMessageType, TraceMessage))
561         {
562             assert(_maxLogCount > 0);
563             if(_logCount == _maxLogCount)
564             {
565                 //
566                 // Need to remove the oldest log from the queue
567                 //
568                 assert(_oldestLog != _queue.end());
569                 _oldestLog = _queue.erase(_oldestLog);
570                 while(_oldestLog != _queue.end() && _oldestLog->type == ICE_ENUM(LogMessageType, TraceMessage))
571                 {
572                     _oldestLog++;
573                 }
574                 assert(_oldestLog != _queue.end());
575             }
576             else
577             {
578                 assert(_logCount < _maxLogCount);
579                 _logCount++;
580                 if(_oldestLog == _queue.end())
581                 {
582                     _oldestLog = p;
583                 }
584             }
585         }
586         else
587         {
588             assert(_maxTraceCount > 0);
589             if(_traceCount == _maxTraceCount)
590             {
591                 //
592                 // Need to remove the oldest trace from the queue
593                 //
594                 assert(_oldestTrace != _queue.end());
595                 _oldestTrace = _queue.erase(_oldestTrace);
596                 while(_oldestTrace != _queue.end() && _oldestTrace->type != ICE_ENUM(LogMessageType, TraceMessage))
597                 {
598                     _oldestTrace++;
599                 }
600                 assert(_oldestTrace != _queue.end());
601             }
602             else
603             {
604                 assert(_traceCount < _maxTraceCount);
605                 _traceCount++;
606                 if(_oldestTrace == _queue.end())
607                 {
608                     _oldestTrace = p;
609                 }
610             }
611         }
612 
613         //
614         // Queue updated, now find which remote loggers want this message
615         //
616         for(RemoteLoggerMap::const_iterator q = _remoteLoggerMap.begin(); q != _remoteLoggerMap.end(); ++q)
617         {
618             const Filters& filters = q->second;
619 
620             if(filters.messageTypes.empty() || filters.messageTypes.count(logMessage.type) != 0)
621             {
622                 if(logMessage.type != ICE_ENUM(LogMessageType, TraceMessage) || filters.traceCategories.empty() ||
623                    filters.traceCategories.count(logMessage.traceCategory) != 0)
624                 {
625                     remoteLoggers.push_back(q->first);
626                 }
627             }
628         }
629     }
630     return remoteLoggers;
631 }
632 
633 void
deadRemoteLogger(const RemoteLoggerPrxPtr & remoteLogger,const LoggerPtr & logger,const LocalException & ex,const string & operation)634 LoggerAdminI::deadRemoteLogger(const RemoteLoggerPrxPtr& remoteLogger,
635                                const LoggerPtr& logger,
636                                const LocalException& ex,
637                                const string& operation)
638 {
639     //
640     // No need to convert remoteLogger as we only use its identity
641     //
642     if(removeRemoteLogger(remoteLogger))
643     {
644         if(_traceLevel > 0)
645         {
646             Trace trace(logger, traceCategory);
647             trace << "detached `" << remoteLogger << "' because " << operation << " raised:\n" << ex;
648         }
649     }
650 }
651 
652 bool
removeRemoteLogger(const RemoteLoggerPrxPtr & remoteLogger)653 LoggerAdminI::removeRemoteLogger(const RemoteLoggerPrxPtr& remoteLogger)
654 {
655     IceUtil::Mutex::Lock lock(_mutex);
656     return _remoteLoggerMap.erase(remoteLogger) > 0;
657 }
658 
659 #ifndef ICE_CPP11_MAPPING
660 //
661 // begin_init callback method for C++98 mapping
662 //
663 void
initCompleted(const AsyncResultPtr & r)664 LoggerAdminI::initCompleted(const AsyncResultPtr& r)
665 {
666     RemoteLoggerPrxPtr remoteLogger = ICE_UNCHECKED_CAST(RemoteLoggerPrx, r->getProxy());
667 
668     try
669     {
670         remoteLogger->end_init(r);
671 
672         if(_traceLevel > 1)
673         {
674             LoggerPtr logger = ICE_DYNAMIC_CAST(Logger, r->getCookie());
675             Trace trace(logger, traceCategory);
676             trace << r->getOperation() << " on `" << remoteLogger << "' completed successfully";
677         }
678     }
679     catch(const LocalException& ex)
680     {
681         deadRemoteLogger(remoteLogger, ICE_DYNAMIC_CAST(Logger, r->getCookie()), ex, r->getOperation());
682     }
683 }
684 #endif
685 
686 //
687 // LoggerAdminLoggerI
688 //
689 
LoggerAdminLoggerI(const PropertiesPtr & props,const LoggerPtr & localLogger)690 LoggerAdminLoggerI::LoggerAdminLoggerI(const PropertiesPtr& props,
691                                        const LoggerPtr& localLogger) :
692     _loggerAdmin(new LoggerAdminI(props)),
693     _destroyed(false)
694 {
695     //
696     // There is currently no way to have a null local logger
697     //
698     assert(localLogger != 0);
699 
700     LoggerAdminLoggerI* wrapper = dynamic_cast<LoggerAdminLoggerI*>(localLogger.get());
701     if(wrapper)
702     {
703         // use the underlying local logger
704        _localLogger = wrapper->getLocalLogger();
705     }
706     else
707     {
708         _localLogger = localLogger;
709     }
710 }
711 
712 void
print(const string & message)713 LoggerAdminLoggerI::print(const string& message)
714 {
715    LogMessage logMessage = { ICE_ENUM(LogMessageType, PrintMessage), IceUtil::Time::now().toMicroSeconds(), "", message };
716 
717     _localLogger->print(message);
718     log(logMessage);
719 }
720 
721 void
trace(const string & category,const string & message)722 LoggerAdminLoggerI::trace(const string& category, const string& message)
723 {
724     LogMessage logMessage = { ICE_ENUM(LogMessageType, TraceMessage), IceUtil::Time::now().toMicroSeconds(), category, message };
725 
726     _localLogger->trace(category, message);
727     log(logMessage);
728 }
729 
730 void
warning(const string & message)731 LoggerAdminLoggerI::warning(const string& message)
732 {
733     LogMessage logMessage = { ICE_ENUM(LogMessageType, WarningMessage), IceUtil::Time::now().toMicroSeconds(), "", message };
734 
735     _localLogger->warning(message);
736     log(logMessage);
737 }
738 
739 void
error(const string & message)740 LoggerAdminLoggerI::error(const string& message)
741 {
742     LogMessage logMessage = { ICE_ENUM(LogMessageType, ErrorMessage), IceUtil::Time::now().toMicroSeconds(), "", message };
743 
744     _localLogger->error(message);
745     log(logMessage);
746 }
747 
748 string
getPrefix()749 LoggerAdminLoggerI::getPrefix()
750 {
751     return _localLogger->getPrefix();
752 }
753 
754 LoggerPtr
cloneWithPrefix(const string & prefix)755 LoggerAdminLoggerI::cloneWithPrefix(const string& prefix)
756 {
757     return _localLogger->cloneWithPrefix(prefix);
758 }
759 
760 ObjectPtr
getFacet() const761 LoggerAdminLoggerI::getFacet() const
762 {
763     return _loggerAdmin;
764 }
765 
766 void
log(const LogMessage & logMessage)767 LoggerAdminLoggerI::log(const LogMessage& logMessage)
768 {
769     const vector<RemoteLoggerPrxPtr> remoteLoggers = _loggerAdmin->log(logMessage);
770 
771     if(!remoteLoggers.empty())
772     {
773         IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_monitor);
774 
775         if(!_sendLogThread)
776         {
777             _sendLogThread = new SendLogThread(ICE_SHARED_FROM_THIS);
778             _sendLogThread->start();
779         }
780 
781         _jobQueue.push_back(new Job(remoteLoggers, logMessage));
782         _monitor.notifyAll();
783     }
784 }
785 
786 void
destroy()787 LoggerAdminLoggerI::destroy()
788 {
789     IceUtil::ThreadControl sendLogThreadControl;
790     bool joinThread = false;
791     {
792         IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_monitor);
793 
794         if(_sendLogThread)
795         {
796             joinThread = true;
797             sendLogThreadControl = _sendLogThread->getThreadControl();
798             _sendLogThread = 0;
799             _destroyed = true;
800             _monitor.notifyAll();
801         }
802     }
803 
804     if(joinThread)
805     {
806         sendLogThreadControl.join();
807     }
808 
809      // destroy sendLogCommunicator
810     _loggerAdmin->destroy();
811 }
812 
813 void
run()814 LoggerAdminLoggerI::run()
815 {
816     if(_loggerAdmin->getTraceLevel() > 1)
817     {
818         Trace trace(_localLogger, traceCategory);
819         trace << "send log thread started";
820     }
821 
822 #ifndef ICE_CPP11_MAPPING
823     CallbackPtr logCompletedCb = newCallback(this, &LoggerAdminLoggerI::logCompleted);
824 #endif
825 
826     for(;;)
827     {
828         IceUtil::Monitor<IceUtil::Mutex>::Lock lock(_monitor);
829         while(!_destroyed && _jobQueue.empty())
830         {
831             _monitor.wait();
832         }
833         if(_destroyed)
834         {
835             break; // for(;;)
836         }
837 
838         assert(!_jobQueue.empty());
839         JobPtr job = _jobQueue.front();
840         _jobQueue.pop_front();
841         lock.release();
842 
843         for(vector<RemoteLoggerPrxPtr>::const_iterator p = job->remoteLoggers.begin(); p != job->remoteLoggers.end(); ++p)
844         {
845             if(_loggerAdmin->getTraceLevel() > 1)
846             {
847                 Trace trace(_localLogger, traceCategory);
848                 trace << "sending log message to `" << *p << "'";
849             }
850 
851             try
852             {
853 #ifdef ICE_CPP11_MAPPING
854                 RemoteLoggerPrxPtr remoteLogger = *p;
855                 auto self = shared_from_this();
856                 remoteLogger->logAsync(job->logMessage,
857                     [self, remoteLogger]()
858                     {
859                         if(self->_loggerAdmin->getTraceLevel() > 1)
860                         {
861                             Trace trace(self->_localLogger, traceCategory);
862                             trace << "log on `" << remoteLogger << "' completed successfully";
863                         }
864                     },
865                     [self, remoteLogger](exception_ptr e)
866                     {
867                         try
868                         {
869                             rethrow_exception(e);
870                         }
871                         catch(const CommunicatorDestroyedException&)
872                         {
873                             // expected if there are outstanding calls during communicator destruction
874                         }
875                         catch(const LocalException& ex)
876                         {
877                             self->_loggerAdmin->deadRemoteLogger(remoteLogger, self->_localLogger, ex, "log");
878                         }
879                     });
880 #else
881                 //
882                 // *p is a proxy associated with the _sendLogCommunicator
883                 //
884                 (*p)->begin_log(job->logMessage, logCompletedCb);
885 #endif
886             }
887             catch(const LocalException& ex)
888             {
889                 _loggerAdmin->deadRemoteLogger(*p, _localLogger, ex, "log");
890             }
891         }
892     }
893 
894     if(_loggerAdmin->getTraceLevel() > 1)
895     {
896         Trace trace(_localLogger, traceCategory);
897         trace << "send log thread completed";
898     }
899 }
900 
901 #ifndef ICE_CPP11_MAPPING
902 //
903 // begin_log callback for C++98 mapping
904 //
905 void
logCompleted(const AsyncResultPtr & r)906 LoggerAdminLoggerI::logCompleted(const AsyncResultPtr& r)
907 {
908     RemoteLoggerPrxPtr remoteLogger = ICE_UNCHECKED_CAST(RemoteLoggerPrx, r->getProxy());
909 
910     try
911     {
912         remoteLogger->end_log(r);
913 
914         if(_loggerAdmin->getTraceLevel() > 1)
915         {
916             Trace trace(_localLogger, traceCategory);
917             trace << r->getOperation() << " on `" << remoteLogger << "' completed successfully";
918         }
919     }
920     catch(const CommunicatorDestroyedException&)
921     {
922         // expected if there are outstanding calls during communicator destruction
923     }
924     catch(const LocalException& ex)
925     {
926         _loggerAdmin->deadRemoteLogger(remoteLogger, _localLogger, ex, r->getOperation());
927     }
928 }
929 #endif
930 
931 //
932 // SendLogThread
933 //
934 
SendLogThread(const LoggerAdminLoggerIPtr & logger)935 SendLogThread::SendLogThread(const LoggerAdminLoggerIPtr& logger) :
936     IceUtil::Thread("Ice.SendLogThread"),
937     _logger(logger)
938 {
939 }
940 
941 void
run()942 SendLogThread::run()
943 {
944     _logger->run();
945 }
946 }
947 
948 //
949 // createLoggerAdminLogger
950 //
951 
952 namespace IceInternal
953 {
954 
955 LoggerAdminLoggerPtr
createLoggerAdminLogger(const PropertiesPtr & props,const LoggerPtr & localLogger)956 createLoggerAdminLogger(const PropertiesPtr& props,
957                         const LoggerPtr& localLogger)
958 {
959     return ICE_MAKE_SHARED(LoggerAdminLoggerI, props, localLogger);
960 }
961 
962 }
963