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